narrow-chef-71655
02/26/2026, 7:17 AMtall-airline-16756
02/26/2026, 7:17 AMtall-airline-16756
02/26/2026, 7:17 AMkind of agent and uses the lk.publish_on_behalf attribute to indicate which agent it’s publishing for:
◦ The original agent participant has lk.publish_on_behalf set to null.
◦ The avatar worker has lk.publish_on_behalf set to the original agent’s identity.
If you’d like, I can show a short code snippet for detecting the agent vs. avatar worker in your frontend (e.g., TypeScript) or help you filter avatar participants in your UI. Which frontend platform are you using?
Sources: Virtual avatar models overview | LiveKit Documentationnarrow-chef-71655
02/26/2026, 7:22 AMtall-airline-16756
02/26/2026, 7:22 AMkind set to agent.
• Use the lk.publish_on_behalf attribute:
◦ The original agent participant has lk.publish_on_behalf = null.
◦ The avatar worker has lk.publish_on_behalf = <agent_identity> indicating it publishes on behalf of the agent.
Example detection logic (conceptual; adapt to your SDK/language):
• On the client (or any backend using the LiveKit room participant list):
a. Find the original agent:
• participant.kind === 'agent' && participant.attributes['lk.publish_on_behalf'] === null
a. Find the avatar worker:
• participant.kind === 'agent' && participant.attributes['lk.publish_on_behalf'] === agent.identity
If you want, I can:
• Provide a concrete code snippet for your SDK/language (e.g., JavaScript/TypeScript, Go, or Python).
• Show how to filter avatar participants in your UI or backend logic (e.g., routing media, applying permissions, or analytics).
Which SDK/language are you using on the client and backend?narrow-chef-71655
02/26/2026, 7:25 AMtall-airline-16756
02/26/2026, 7:25 AMfrom livekit import rtc
# assume `room` is your connected Room instance
@room.on("track_published")
def on_track_published(publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
# publication.track may be None until the track is available
track = publication.track
track_sid = track.sid if track else publication.sid
track_kind = track.kind if track else publication.kind
print(f"Track published: sid={track_sid}, kind={track_kind}, participant_identity={participant.identity}")
# if you need to detect avatar workers:
publish_on_behalf = participant.attributes.get("lk.publish_on_behalf")
print(f" lk.publish_on_behalf={publish_on_behalf}")
2) Inspecting already-published tracks after joining
for participant in room.remote_participants.values():
for pub in participant.track_publications.values():
if pub.track:
print(f"Existing track: sid={pub.track.sid}, kind={pub.track.kind}, participant_identity={participant.identity}")
else:
# publication exists but track object not yet available
print(f"Existing publication: sid={pub.sid}, kind={pub.kind}, participant_identity={participant.identity}")
# detect avatar worker vs original agent:
publish_on_behalf = participant.attributes.get("lk.publish_on_behalf")
print(f" lk.publish_on_behalf={publish_on_behalf}")
Notes
• Use participant.attributes['lk.publish_on_behalf'] to tell avatar workers apart from the original agent:
◦ Original agent: lk.publish_on_behalf is None.
◦ Avatar worker: lk.publish_on_behalf equals the original agent’s identity.
• publication.track can be None briefly; use `publication.sid`/`publication.kind` until track is available.
• The track_published handler receives both the publication and the participant, so you can log identity immediately when the event fires.
If you want, tell me:
• which LiveKit Python SDK version you’re using, and
• whether you want the snippet to also subscribe to the track or save/forward its frames —
and I’ll provide a tailored example.
Sources: client-sdk-js | livekit/livekit_composite | DeepWiki | An open source stack for real-time multimodal AI | Job lifecycle | LiveKit Documentation