# WoW Combat Log Format Specification # Canonical URL: https://wowcoach.gg/docs/combat-log # Cite as: WoW Combat Log Reference (WowCoach.gg). https://wowcoach.gg/docs/combat-log # # This is a machine-readable specification of the WoW combat log format itself. # Field offsets verified against real retail M+ and raid logs. # JSON version: https://wowcoach.gg/docs/combat-log/spec.json # # Living document — updated as the format evolves. $schema: https://wowcoach.gg/docs/combat-log/spec.json format_version: 22 verified_against_patch: 12.0+ last_updated: 2026-05-08 notes: This is the WoW combat log format itself — what Blizzard emits to the client log file. Field offsets verified against real retail M+ and raid logs. The structure is stable across expansions; exact offsets may shift between major patches. source: canonical_url: https://wowcoach.gg/docs/combat-log cite_as: WoW Combat Log Reference (WowCoach.gg). https://wowcoach.gg/docs/combat-log line_format: separator: two spaces (or tab on some clients) between timestamp and event CSV timestamp_format: M/D/YYYY HH:MM:SS.fff±Z (locale-dependent date order) csv: quote_char: '"' embedded_comma: allowed inside quoted strings nil_literal: the string "nil" stands in for "no value" / null in many fields version_header: example: COMBAT_LOG_VERSION,22,ADVANCED_LOG_ENABLED,1,BUILD_VERSION,12.0.0,PROJECT_ID,1 fields: - name: format_version type: integer - name: advanced_log_enabled type: boolean_int - name: build_version type: string - name: project_id type: integer notes: 1 for retail common_header: applies_to: all events with a source/target fields: - offset: 0 name: event type: string - offset: 1 name: source_guid type: string - offset: 2 name: source_name type: quoted_string - offset: 3 name: source_flags type: hex_uint32 enumRef: unit_flags - offset: 4 name: source_raid_flags type: hex_uint32 enumRef: raid_marker_flags - offset: 5 name: dest_guid type: string - offset: 6 name: dest_name type: quoted_string - offset: 7 name: dest_flags type: hex_uint32 enumRef: unit_flags - offset: 8 name: dest_raid_flags type: hex_uint32 enumRef: raid_marker_flags spell_prefix: applies_to: events whose name starts with SPELL_, RANGE_, or SPELL_PERIODIC_ (not SWING_*) fields: - offset: 9 name: spell_id type: integer - offset: 10 name: spell_name type: quoted_string - offset: 11 name: spell_school type: hex_bitfield enumRef: spell_schools advanced_logging_block: size: 19 enabled_by: /console advancedCombatLogging 1 detection_hint: "Count fields on a SPELL_DAMAGE event: ~22 fields = off, 40+ fields = on. Do not trust the ADVANCED_LOG_ENABLED header on a fragmented log." position: - event_pattern: SPELL_*, RANGE_* offsets: 12-30 - event_pattern: SWING_* offsets: 9-27 - event_pattern: ENVIRONMENTAL_DAMAGE offsets: 9-27 describes: - event: SPELL_DAMAGE unit: target - event: SPELL_PERIODIC_DAMAGE unit: target - event: RANGE_DAMAGE unit: target - event: SPELL_HEAL unit: target - event: SPELL_PERIODIC_HEAL unit: target - event: SWING_DAMAGE unit: source - event: SWING_DAMAGE_LANDED unit: target - event: ENVIRONMENTAL_DAMAGE unit: target - event: SPELL_ENERGIZE unit: target fields: - offset: 0 name: info_guid type: string notes: Identifies which unit this block describes — match against source/dest GUID. - offset: 1 name: owner_guid type: string notes: Pet owner GUID, or 0000000000000000 if not a pet. - offset: 2 name: current_hp type: long - offset: 3 name: max_hp type: long - offset: 4 name: attack_power type: integer - offset: 5 name: spell_power type: integer - offset: 6 name: armor type: integer - offset: 7 name: absorb type: integer - offset: 8 name: unknown_1 type: integer notes: Always 0 in observed retail logs. - offset: 9 name: unknown_2 type: integer notes: Always 0 in observed retail logs. - offset: 10 name: power_type type: integer enumRef: power_types - offset: 11 name: current_power type: integer - offset: 12 name: max_power type: integer - offset: 13 name: power_cost type: integer notes: In tenths (e.g., 350 = 35 rage). - offset: 14 name: position_x type: float - offset: 15 name: position_y type: float - offset: 16 name: ui_map_id type: integer - offset: 17 name: facing type: float notes: Radians. - offset: 18 name: item_level type: integer guid_prefixes: - prefix: Player- meaning: Player character example: Player-1168-0A234B - prefix: Pet- meaning: Hunter pet, ghoul, elemental, mirror image, voidwalker example: Pet-0-4232-2662-31585-165189-... - prefix: Creature- meaning: "Any NPC: trash, boss, friendly NPC. NPC entry ID is the second-to-last segment." example: Creature-0-4232-2662-31585-214502-0001 - prefix: Vehicle- meaning: Siege weapons, dungeon vehicles, possession vehicles example: Vehicle-0-4232-... - prefix: GameObject- meaning: Interactable object example: GameObject-0-... - prefix: "0000000000000000" meaning: No source/target (used by environmental events) example: "0000000000000000" events: SPELL_DAMAGE: prefix: spell_prefix hasAdvancedBlock: true totalFieldCount: 42 advancedBlockDescribes: target suffix: - offset: 31 name: base_amount type: integer notes: Effective damage post-mitigation. The canonical damage number. - offset: 32 name: raw_amount type: integer notes: Pre-mitigation, diagnostics only. - offset: 33 name: overkill type: integer notes: -1 if not a killing blow; otherwise excess damage past 0 HP. - offset: 34 name: school type: hex_bitfield enumRef: spell_schools - offset: 35 name: resisted type: integer - offset: 36 name: blocked type: integer - offset: 37 name: absorbed type: integer notes: Informational. Do NOT add to totals — use the SPELL_ABSORBED event. - offset: 38 name: critical type: bool_or_nil - offset: 39 name: glancing type: bool_or_nil notes: Legacy, always nil in modern logs. - offset: 40 name: crushing type: bool_or_nil notes: Legacy, always nil in modern logs. - offset: 41 name: ability_hint type: string values: - ST - AOE notes: Tag from the game indicating single-target vs cleave/AoE. SPELL_PERIODIC_DAMAGE: inherits: SPELL_DAMAGE notes: DoT tick. Identical layout. RANGE_DAMAGE: inherits: SPELL_DAMAGE SPELL_DAMAGE_SUPPORT: inherits: SPELL_DAMAGE notes: Augmentation Evoker buffed damage. Last field is the supporting Aug Evoker player GUID. SPELL_PERIODIC_DAMAGE_SUPPORT: inherits: SPELL_DAMAGE_SUPPORT RANGE_DAMAGE_SUPPORT: inherits: SPELL_DAMAGE_SUPPORT SWING_DAMAGE: hasSpellPrefix: false hasAdvancedBlock: true totalFieldCount: 38 (or 39 if off-hand) advancedBlockDescribes: source suffix: - offset: 28 name: base_amount type: integer - offset: 29 name: raw_amount type: integer - offset: 30 name: overkill type: integer - offset: 31 name: school type: hex_bitfield notes: Always 0x1 (physical). - offset: 32 name: resisted type: integer - offset: 33 name: blocked type: integer - offset: 34 name: absorbed type: integer - offset: 35 name: critical type: bool_or_nil - offset: 36 name: glancing type: bool_or_nil - offset: 37 name: crushing type: bool_or_nil - offset: 38 name: is_off_hand type: bool_or_nil optional: true notes: Field is omitted entirely for main-hand swings. SWING_DAMAGE_LANDED: inherits: SWING_DAMAGE advancedBlockDescribes: target notes: SAME swing as SWING_DAMAGE, reported again with the target advanced block. Do NOT count both. ENVIRONMENTAL_DAMAGE: hasSpellPrefix: false hasAdvancedBlock: true totalFieldCount: 39 advancedBlockDescribes: target notes: Source GUID is always 0000000000000000. suffix: - offset: 28 name: environmental_type type: string values: - Falling - Lava - Fire - Slime - Drowning - Fatigue - offset: 29 name: base_amount type: integer - offset: 30 name: raw_amount type: integer - offset: 31 name: overkill type: integer - offset: 32 name: school type: hex_bitfield - offset: 33 name: resisted type: integer - offset: 34 name: blocked type: integer - offset: 35 name: absorbed type: integer - offset: 36 name: critical type: bool_or_nil - offset: 37 name: glancing type: bool_or_nil - offset: 38 name: crushing type: bool_or_nil SPELL_HEAL: prefix: spell_prefix hasAdvancedBlock: true totalFieldCount: 36 advancedBlockDescribes: target suffix: - offset: 31 name: healed_to_hp type: integer notes: Raw heal minus shield-converted portion. NOT the canonical heal amount. - offset: 32 name: amount type: integer notes: Total healing INCLUDING overheal. The canonical heal amount. - offset: 33 name: overheal type: integer - offset: 34 name: absorbed_to_shield type: integer notes: Already inside `amount` — do not subtract. - offset: 35 name: critical type: bool_or_nil SPELL_PERIODIC_HEAL: inherits: SPELL_HEAL SPELL_HEAL_SUPPORT: inherits: SPELL_HEAL notes: Augmentation Evoker buffed healing. Last field is the supporting Aug Evoker player GUID. SPELL_ABSORBED: hasSpellPrefix: false hasAdvancedBlock: false notes: "Variable arity: 19 fields when defender == absorber, 22 fields when shield is on someone else. Count fields to disambiguate." variants: - when: field_count >= 22 (shield on a different unit than the defender) totalFieldCount: 22 suffix: - offset: 1-4 name: attacker type: unit_block - offset: 5-8 name: defender type: unit_block - offset: 9-11 name: damage_spell type: spell_block - offset: 12-15 name: absorber type: unit_block - offset: 16-18 name: shield_spell type: spell_block - offset: 19 name: amount type: integer - offset: 20 name: total_amount type: integer notes: Full attempted damage before absorb. - offset: 21 name: critical type: bool_or_nil - when: field_count == 19 (self-shield) totalFieldCount: 19 suffix: - offset: 1-4 name: attacker type: unit_block - offset: 5-8 name: defender type: unit_block - offset: 9-12 name: absorber type: unit_block notes: Same as defender. - offset: 13-15 name: shield_spell type: spell_block - offset: 16 name: amount type: integer - offset: 17 name: total_amount type: integer - offset: 18 name: critical type: bool_or_nil SPELL_HEAL_ABSORBED: notes: Healing absorbed by a heal-absorb debuff. Layout follows the SPELL_ABSORBED conventions. SPELL_AURA_APPLIED: prefix: spell_prefix hasAdvancedBlock: false totalFieldCount: 13 or 14 suffix: - offset: 12 name: aura_type type: string values: - BUFF - DEBUFF - offset: 13 name: amount type: integer optional: true notes: "Absorb amount for shield buffs (Power Word: Shield, Reflective Shield). Absent for most auras. NOT a stack count." SPELL_AURA_REMOVED: inherits: SPELL_AURA_APPLIED SPELL_AURA_REFRESH: inherits: SPELL_AURA_APPLIED SPELL_AURA_BROKEN: inherits: SPELL_AURA_APPLIED notes: Aura removed by damage (Polymorph, Sap). SPELL_AURA_BROKEN_SPELL: inherits: SPELL_AURA_APPLIED notes: Aura broken by a specific dispel/cleanse. SPELL_AURA_APPLIED_DOSE: prefix: spell_prefix hasAdvancedBlock: false suffix: - offset: 12 name: aura_type type: string - offset: 13 name: stacks type: integer notes: Stack count after the application. SPELL_AURA_REMOVED_DOSE: inherits: SPELL_AURA_APPLIED_DOSE SPELL_INTERRUPT: prefix: spell_prefix hasAdvancedBlock: false totalFieldCount: 15 suffix: - offset: 12 name: interrupted_spell_id type: integer - offset: 13 name: interrupted_spell_name type: quoted_string - offset: 14 name: interrupted_spell_school type: hex_bitfield enumRef: spell_schools SPELL_DISPEL: prefix: spell_prefix hasAdvancedBlock: false suffix: - offset: 12 name: dispelled_spell_id type: integer - offset: 13 name: dispelled_spell_name type: quoted_string - offset: 14 name: dispelled_spell_school type: hex_bitfield - offset: 15 name: aura_type type: string values: - BUFF - DEBUFF SPELL_STOLEN: inherits: SPELL_DISPEL SPELL_ENERGIZE: prefix: spell_prefix hasAdvancedBlock: true advancedBlockDescribes: target suffix: - offset: 31 name: amount type: integer - offset: 32 name: over_energize type: integer - offset: 33 name: power_type type: integer enumRef: power_types - offset: 34 name: max_power type: integer notes: Maximum power pool. NOT current power. SPELL_DRAIN: inherits: SPELL_ENERGIZE SPELL_LEECH: inherits: SPELL_ENERGIZE SPELL_PERIODIC_ENERGIZE: inherits: SPELL_ENERGIZE SPELL_CAST_START: prefix: spell_prefix hasAdvancedBlock: false SPELL_CAST_SUCCESS: prefix: spell_prefix hasAdvancedBlock: true notes: This is the event that fires the ability. Damage events come later. SPELL_CAST_FAILED: prefix: spell_prefix hasAdvancedBlock: false suffix: - offset: 12 name: fail_reason type: string notes: 'Localized: "Out of range", "Not yet recovered", etc.' SWING_MISSED: hasSpellPrefix: false hasAdvancedBlock: false suffix: - offset: 9 name: miss_type type: string enumRef: miss_types SPELL_MISSED: prefix: spell_prefix hasAdvancedBlock: false suffix: - offset: 12 name: miss_type type: string enumRef: miss_types RANGE_MISSED: inherits: SPELL_MISSED SPELL_SUMMON: prefix: spell_prefix hasAdvancedBlock: false notes: Source summons target via spell. Authoritative pet ownership signal. SPELL_RESURRECT: prefix: spell_prefix hasAdvancedBlock: false SPELL_INSTAKILL: prefix: spell_prefix notes: Forced kill effect (e.g., Purgatory expiring). Use for death analysis. DAMAGE_SPLIT: notes: Damage split among multiple targets (defensive/support mechanic). Exclude from offensive damage totals. UNIT_DIED: hasSpellPrefix: false hasAdvancedBlock: false UNIT_DESTROYED: hasSpellPrefix: false hasAdvancedBlock: false notes: Pet/totem/object was destroyed (not killed). UNIT_DISSIPATES: hasSpellPrefix: false hasAdvancedBlock: false notes: For things that fade out (totems expiring). UNIT_HEALTH: noSourceTarget: true notes: Boss / unit HP update. Useful for HP timelines. ENCOUNTER_START: noSourceTarget: true suffix: - offset: 1 name: encounter_id type: integer notes: Blizzard's DungeonEncounter ID (DungeonEncounter.db2). - offset: 2 name: encounter_name type: quoted_string - offset: 3 name: difficulty_id type: integer enumRef: difficulties - offset: 4 name: group_size type: integer - offset: 5 name: instance_id type: integer optional: true ENCOUNTER_END: noSourceTarget: true suffix: - offset: 1 name: encounter_id type: integer - offset: 2 name: encounter_name type: quoted_string - offset: 3 name: difficulty_id type: integer - offset: 4 name: group_size type: integer - offset: 5 name: success type: boolean_int notes: 1 = kill, 0 = wipe. - offset: 6 name: duration_ms type: integer optional: true CHALLENGE_MODE_START: noSourceTarget: true suffix: - offset: 1 name: dungeon_name type: quoted_string - offset: 2 name: map_id type: integer - offset: 3 name: challenge_mode_id type: integer - offset: 4 name: keystone_level type: integer - offset: 5 name: affixes type: integer_array CHALLENGE_MODE_END: noSourceTarget: true suffix: - offset: 1 name: map_id type: integer - offset: 2 name: success type: boolean_int - offset: 3 name: keystone_level type: integer - offset: 4 name: total_time_ms type: integer optional: true - offset: 5 name: on_time_seconds type: float optional: true notes: Positive = ahead of timer; negative = behind. - offset: 6 name: timer_limit_seconds type: integer optional: true ZONE_CHANGE: noSourceTarget: true suffix: - offset: 1 name: zone_id type: integer - offset: 2 name: zone_name type: quoted_string - offset: 3 name: instance_type type: integer MAP_CHANGE: noSourceTarget: true suffix: - offset: 1 name: ui_map_id type: integer - offset: 2 name: map_name type: quoted_string - offset: 3 name: max_x type: float - offset: 4 name: min_x type: float - offset: 5 name: max_y type: float - offset: 6 name: min_y type: float WORLD_MARKER_PLACED: noSourceTarget: true suffix: - offset: 1 name: instance_id type: integer - offset: 2 name: marker_index type: integer enumRef: world_markers - offset: 3 name: x type: float - offset: 4 name: y type: float WORLD_MARKER_REMOVED: noSourceTarget: true suffix: - offset: 1 name: instance_id type: integer - offset: 2 name: marker_index type: integer COMBATANT_INFO: noSourceTarget: true notes: Mixed CSV + bracket arrays + tuples. Fired at encounter start, one per player. csvPortion: - offset: 1 name: player_guid type: string - offset: 3 name: primary_stat type: integer notes: Strength, Agility, or Intellect — same field, varies by class. - offset: 5 name: stamina type: integer - offset: 10 name: crit_rating type: integer notes: Triplicate at offsets 10, 11, 12. - offset: 13 name: speed_rating type: integer - offset: 14 name: leech_rating type: integer - offset: 15 name: haste_rating type: integer notes: Triplicate at offsets 15, 16, 17. - offset: 18 name: avoidance_rating type: integer - offset: 19 name: mastery_rating type: integer - offset: 20 name: versatility_rating type: integer notes: Triplicate at offsets 20, 21, 22. - offset: 24 name: spec_id type: integer enumRef: spec_ids bracketPortion: - position: 1 shape: "[(node_id, entry_id, rank), ...]" name: talents notes: rank=0 = tree slot allocated but not chosen. Middle field is TraitNodeEntry ID, NOT spell ID. - position: 2 shape: (pvp1, pvp2, ...) name: pvp_talents notes: A tuple, NOT a bracket array. - position: 3 shape: "[(item_id, ilvl, (enchants), (bonus_ids), (gems)), ...]" name: gear notes: Array index = equipment slot. item_id=0 = empty slot. - position: 4 shape: "[(source_guid, spell_id, ...), ...]" name: active_auras COMBAT_LOG_VERSION: noSourceTarget: true notes: Header line. Can appear mid-log if the logger restarted (treat as a hard boundary — reset accumulated state). enums: spell_schools: type: hex_bitfield values: "0x1": Physical "0x2": Holy "0x4": Fire "0x8": Nature "0x10": Frost "0x20": Shadow "0x40": Arcane power_types: type: integer values: "0": Mana "1": Rage "2": Focus "3": Energy "4": ComboPoints "5": Runes "6": RunicPower "7": SoulShards "8": LunarPower "9": HolyPower "11": Maelstrom "12": Chi "13": Insanity "16": ArcaneCharges "17": Fury "18": Pain "19": Essence unit_flags: type: hex_bitfield structure: affiliation: mask: "0x00F" values: "0x1": Mine "0x2": Party "0x4": Raid "0x8": Outsider reaction: mask: "0x0F0" values: "0x10": Friendly "0x20": Neutral "0x40": Hostile control: mask: "0xF00" values: "0x100": PlayerControlled "0x200": NPCControlled unit_type: mask: "0xF000" values: "0x400": Player "0x800": NPC "0x1000": Pet "0x2000": Guardian "0x4000": Object raid_marker_flags: type: hex_bitfield values: "0x01": Star "0x02": Circle "0x04": Diamond "0x08": Triangle "0x10": Moon "0x20": Square "0x40": Cross "0x80": Skull miss_types: type: string values: - MISS - DODGE - PARRY - BLOCK - DEFLECT - IMMUNE - ABSORB - REFLECT - EVADE - RESIST difficulties: type: integer values: "8": Mythic_Plus "14": Normal_Raid "15": Heroic_Raid "16": Mythic_Raid "17": LFR world_markers: type: integer values: "1": Star "2": Circle "3": Diamond "4": Triangle "5": Moon "6": Square "7": Cross "8": Skull spec_ids: DeathKnight: "250": Blood "251": Frost "252": Unholy DemonHunter: "577": Havoc "581": Vengeance "1480": Devourer Druid: "102": Balance "103": Feral "104": Guardian "105": Restoration Evoker: "1467": Devastation "1468": Preservation "1473": Augmentation Hunter: "253": BeastMastery "254": Marksmanship "255": Survival Mage: "62": Arcane "63": Fire "64": Frost Monk: "268": Brewmaster "269": Windwalker "270": Mistweaver Paladin: "65": Holy "66": Protection "70": Retribution Priest: "256": Discipline "257": Holy "258": Shadow Rogue: "259": Assassination "260": Outlaw "261": Subtlety Shaman: "262": Elemental "263": Enhancement "264": Restoration Warlock: "265": Affliction "266": Demonology "267": Destruction Warrior: "71": Arms "72": Fury "73": Protection gotchas: - id: detect-advanced-by-row-width title: Detect advanced logging by row width, not header details: "COMBAT_LOG_VERSION lies on fragmented logs. Count fields on a SPELL_DAMAGE event: ~22 fields = off, 40+ = on." - id: absorbed-field-vs-event title: SPELL_DAMAGE absorbed field vs SPELL_ABSORBED event details: They are different things. The absorbed field on damage events is informational. Use SPELL_ABSORBED as the source of truth. Counting both double-counts partial absorbs. - id: overkill-minus-one title: Overkill is -1 when not killing details: Clamp to zero before subtracting. Negative overkill means "this was not a killing blow." - id: trailing-damage-after-encounter-end title: ENCOUNTER_END is not the end of damage details: DoTs continue ticking ~2 seconds after ENCOUNTER_END. Add a trailing damage window or under-count by 1–3% per fight. - id: talent-entry-id title: COMBATANT_INFO talent ID is the entry ID, not spell ID details: The middle number in each talent triple is the TraitNodeEntry ID, not the trait definition ID. Resolve via wago.tools or wow.tools. - id: mid-log-version-restart title: Mid-log COMBAT_LOG_VERSION = logger restarted details: Treat as a hard boundary. Reset pet ownership, ongoing auras, fight tracking — accumulated state across the seam is wrong. - id: two-spell-absorbed-formats title: Two SPELL_ABSORBED formats details: 22 fields when shield is on someone else (Disc priest absorbing for tank). 19 fields for self-shields. Count fields before parsing. - id: swing-damage-landed-doublecount title: SWING_DAMAGE_LANDED double-counts if you read both details: It is the same swing as SWING_DAMAGE, reported again with the target advanced block. Count one stream, not both. - id: pets-before-summon title: Pets deal damage before SPELL_SUMMON details: Pre-combat pets (warlock demons, hunter pets, DK ghouls) appear before their summon. Buffer unknown-owner pet damage and reassign retroactively. - id: vehicle-possession-guids title: Vehicle and possession GUIDs details: Mind-control / vehicle entry changes the source GUID. Follow the ownerGUID chain (offset 1 in advanced block) for attribution. - id: stagger-and-cheat-death-not-healing title: Stagger and cheat-death absorbs are not healing details: "Exclude these spell IDs from healing totals: 114556 Purgatory, 31850 Ardent Defender, 31230 Cheat Death, 115069 Stagger." - id: aura-stacks-only-on-dose-events title: Aura stack field is only valid on _DOSE events details: For non-DOSE aura events the field at offset 13 may carry an absorb amount or be absent. Do not blindly read as stacks. - id: docs-disagree title: Pre-existing combat-log docs disagree with each other details: Older references claim ENVIRONMENTAL_DAMAGE puts envType at field 9 — it is actually field 28. SPELL_DAMAGE has 42 fields with an undocumented ST/AOE hint. Verify against real logs.