in livekit room avatar will be considered as remot...
# ask-ai
n
in livekit room avatar will be considered as remote participant or local participant ?
t
Thanks for reaching out, Darshak. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — great question. I’m responding to whether an avatar in a LiveKit room is treated as a remote or local participant. An avatar is considered a remote participant. • The avatar runs as a separate participant (often called an “avatar worker”) that joins the room and publishes audio/video tracks independently from the original agent. • On the client side you will see the avatar as a remote participant. The avatar worker is marked by the participant
kind
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 Documentation
n
talking from client side (Backend side)
t
Thanks — you clarified you mean both the client side and backend. I’m responding to whether an avatar in a LiveKit room is considered a remote or local participant from both perspectives. Short answer: the avatar is a remote participant on both client and backend. Why: • The avatar runs as a separate participant (an “avatar worker”) that joins the room independently and publishes audio/video tracks. • It is distinct from the original agent participant; the avatar worker publishes on behalf of the agent but is still a separate (remote) participant. How to identify the avatar programmatically: • Look for participants with
kind
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?
n
ha use published track event and print the track and participant identity in python SDK
t
Thanks — I’ll show how to listen for published tracks with the LiveKit Python SDK and print the track info plus the participant identity. This works for regular participants and avatar workers (which appear as remote participants). 1) Listening for newly published tracks
Copy code
from 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
Copy code
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