A small library which keeps track of group members and keeps an up-to-date cache of their specialization and talents.

It's similar to the old LibGroupTalents/LibTalentQuery and the LibRaidInspect libraries, but unlike the former it's actually working on 7.0, and unlike the latter it works properly in Battlegrounds. Additionally it has the feature where it communicates spec/talent updates to other LibGroupInSpecT users. This is an important point as of the writing of this there is no way to detect when another player re-specs/talents.

This library started out as a part of RaidChecklist as replacement for LibGroupTalents, but has since been split off into its own project as its usefulness increases the more widespread it is.

To make use of this library you'll need to also have the usual LibStub and LibCallbackHandler libs.

For a real usage example, take a look at the RaidChecklist project.

Important: WoD version change

As of Sep 18 the trunk development is changing to WoD/6.0 development, with the major version as 1.1. If you need 5.x compatibility, please lock to the 1.0.3 tag.


These events can be registered for using the regular CallbackHandler ways.


"GroupInSpecT_Update"guid, unit, info
"GroupInSpecT_InspectReady"guid, unit


Fires when info is ready or has been modified.
Fires when a member leaves the group.
Fires during INSPECT_READY so that clients can perform supplemental inspection handling (as of r78).


local LGIST = LibStub:GetLibrary("LibGroupInSpecT-1.1")
LGIST.RegisterCallback(addonObject, "GroupInSpecT_Remove", "UnitRemoved")
function addonObject:UnitRemoved(event, guid)
  -- unit with guid removed


Functions for external use:

lib:Rescan (guid or nil)
Force a fresh inspection of all group members. As of r76 it accepts an optional guid parameter, to rescan only a particular GUID rather than all group members.
lib:QueuedInspections ()
Returns an array of GUIDs of outstanding inspects.
lib:StaleInspections ()
Returns an array of GUIDs for which the data has been deemed stale and is awaiting an update (no action required, the refresh happens internally).
lib:GetCachedInfo (guid)
Returns the cached info for the given GUID, if available, nil otherwise. Information is cached for current group members only.
lib:GuidToUnit (guid)
Returns the unit id for the given GUID, provided said GUID represents a current group member, else nil.

info table structure

The fields of the table passed as an argument for "GroupInSpecT_Update" callback or returned by one of the API functions (eg. :GetCachedInfo(guid) ). A list of all the global specialization IDs is available here.

Note: Not all fields may be available at all times due to the Blizz API not returning the info at that point. Incremental updates will be sent, so coding with the possibility of nil in mind is highly advised.

Info structure

  .gender -- 2 = male, 3 = female
  .spec_role_detailed -- "tank", "melee", "ranged" or "healer" (introduced in 1.0.2)
  .spec_group -- active spec group (1/2/nil), introduced in 1.1
  .talents = {
    [<talent_id>] = { -- Note: Since 1.1 this is a talent_id, not a spell_id
      .talent_id -- Introduced in 1.1. This replaces the old 1.0.x .idx entry
  .lku -- last known unit id


Typical usage example.

Libs/LibGroupInSpecT-1.1: svn://


## X-Embeds: LibGroupInSpecT-1.1
## OptionalDeps: LibGroupInSpecT-1.1
[email protected]@
[email protected]@

alternatively embeds.xml (referenced in .toc)

<ui xmlns="" xmlns:xsi="" xsi:schemaLocation="\FrameXML\UI.xsd">
<[email protected]@-->
  <script file="Libs\LibStub\LibStub.lua"/>
  <include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
  <include file="Libs\LibGroupInSpecT-1.1\lib.xml"/>
<[email protected]@-->


local LGIST=LibStub:GetLibrary("LibGroupInSpecT-1.1")
LGIST.RegisterCallback(addonObject, "GroupInSpecT_Update", "UpdateHandler")
LGIST.Registercallback(addonObject, "GroupInSpecT_Remove", "RemoveHandler")
function addonObject:UpdateHandler(event, guid, unit, info)
  if info.class and info.class == "DEATHKNIGHT" and info.spec_role and info.spec_role == "TANK" then
    print(UnitName(unit).." is now " -- may also be available
function addonObject:RemoveHandler(event, guid)
  -- guid no longer a group member
local info = LGIST:GetCachedInfo(guid)
local hasFocusingShot = info and next(info.talents) and info.talents[21729] -- focusing shot talent_id

Main page formatting by Dridzt. Much obliged!

You must login to post a comment. Don't have an account? Register to get one!

  • Avatar of Galedric Galedric May 14, 2016 at 16:59 UTC - 0 likes

    Any plan of updating this lib for Legion?
    If yes, are you planing on having Artifact talent data available?

  • Avatar of antiganon antiganon May 25, 2015 at 00:15 UTC - 0 likes

    Is it possible to have this addon cache a list of items as well? I am trying to make a loot council addon which prints a list of eligible raid members and the item they currently have equipped in that slot.

  • Avatar of mikk mikk Nov 13, 2014 at 02:00 UTC - 0 likes

    This needs release tagging. It's not being pushed to curse client.

  • Avatar of Tokotsi Tokotsi May 29, 2013 at 22:22 UTC - 0 likes

    Take a look at LibSpecRoster here on WowAce, and see how they deal with the spell ID of the talent. Isn't that what is trying to be done here via the tooltip scanning method? Is there a reason to go with one method vs. the other?

    Also, in answer to someone's question about differences between the two libraries, and since I was trying to figure that out myself, I posted what I saw after quick, cursory looks at them both. Given the quick look and lack of experience with either, and in general, I would be interested in feedback from those who've had more experience. I don't want to steer myself or others wrong :)

  • Avatar of Road_Block Road_Block Sep 22, 2012 at 11:35 UTC - 0 likes

    When this has hit its first release, you'd probably want to give it its forum thread here: (Libraries section)

    The Summary part of the project page, maybe the current info table and a link to the project page for further details should be sufficient :-)

    Last edited Sep 22, 2012 by Road_Block
  • Avatar of Anyia3 Anyia3 Sep 16, 2012 at 23:26 UTC - 0 likes

    @oscarucb: As Dridzt said, the 'sender' argument is unfortunately the unqualified character name (i.e. without realm information), so it cannot be reliably used to get the UUID from.

    @Dridzt: I'll have a look at thew new version after work tonight, or tomorrow, with a view of getting this stuff into mainline sooner rather than later.

  • Avatar of Road_Block Road_Block Sep 16, 2012 at 20:49 UTC - 0 likes

    @oscarucb: Go

    Sender is a name not unitid afaik, I'm not sure it always resolves to a guid if for example the sender is in an instance and you're not, or half across the world.

    Not sure and not very easy to test atm (for me).

    In any case I'm almost done with the new alpha, and transmitting the guid doesn't remotely push the message length near the limit.

    Edit: r27 cloned is in.
    Seeing as I've already sunk several hours in this overall, I'm giving it a rest, any improvements or changes be my guest :-p

    Last edited Sep 17, 2012 by Road_Block
  • Avatar of oscarucb oscarucb Sep 16, 2012 at 18:50 UTC - 0 likes

    - unitguid (need this or no way to assign the transmitted info to a unit)

    Wait, why is that? The CHAT_MSG_ADDON event already provides a sender argument that is sent with the message envelope, so isn't this field always equal to UnitGUID(sender)? Sending it explicitly should be redundant..

    Sorry to be picky, just trying to help us come up with the best possible library.

  • Avatar of oscarucb oscarucb Sep 16, 2012 at 15:38 UTC - 0 likes

    The argument about pulling in extra libraries could be used about everything tbh, but libraries only get loaded once, don't think a few extra kb of disk space is an issue at the benefit of being lazy

    It's not an issue of disk space, it's a matter of favoring laziness for the library CLIENT rather than the library WRITER. As an addon author, I dislike using a library that has a bunch of external dependencies and requires me to also suck in a bunch of additional libraries I don't need before the library can do its job. It means additional work for the addon writer to adopt your library and do the packaging correctly (and additional opportunities to get it wrong), and also additional places where version incompatibilities can arise and cause problems. Eg if the API for libgroupinspect changes in some version (or some version-specific bug arises), the addon writer is the direct client of that interface and can ensure he's embedding the working version and using the right call or workaround for the right version. If the API for libcompress were to change (or some version-specific bug arises), the addon writer knows nothing about the calls to that lib or what specific version he should be embedding in order to make libgroupinspect work.

    Speaking of versioning issues, it may be wise to include a (single-digit) comm format version number in the addon comm, in case a future version of libgroupinspect needs to expand or change the format of that comm. Receivers should ignore messages with version numbers higher than what they know how to parse.

  • Avatar of Road_Block Road_Block Sep 16, 2012 at 15:00 UTC - 0 likes

    A typical full infotable compressed is around 1337 bytes.

    Apart from the comedy value of getting a Leet number on my first test, I think I'll take your advice and commit a version at the clone with a custom serializer sending the minimum necessary data and building the full table with API + local lookups upon receipt :-)

    Last edited Sep 16, 2012 by Road_Block


Date created
Sep 01, 2012
Last update
Aug 24, 2016
Development stage
BSD License
Curse link
Reverse relationships
Recent files
  • R: 1.2.1 for 7.0.3 Aug 24, 2016
  • A: r86 for 7.0.3 Aug 24, 2016
  • R: 1.2.0 for 7.0.3 Aug 02, 2016
  • A: r84 for 7.0.3 Jul 30, 2016
  • A: r83 for 7.0.3 Jul 29, 2016



Embedded library