• DocsDocs
  • PricingPricing
Book a demo
Sign in
Sign in
Book a demo
    • Ready-made features
      • AI Copilots
        AI Copilots

        In-app AI agents that feel human

      • Comments
        Comments

        Contextual commenting

      • Multiplayer Editing
        Multiplayer Editing

        Realtime collaboration

      • Notifications
        Notifications

        Smart alerts for your app

      • Presence
        Presence

        Realtime presence indicators

    • Platform
      • Monitoring Dashboard
        Monitoring Dashboard

        Monitor your product

      • Realtime Infrastructure
        Realtime Infrastructure

        Hosted WebSocket infrastructure

    • Tools
      • Examples

        Gallery of open source examples

      • Next.js Starter Kit

        Kickstart your Next.js collaborative app

      • DevTools

        Browser extension for debugging

      • Tutorial

        Step-by-step interactive tutorial

      • Guides

        How-to guides and tutorial

    • Company
      • Blog

        The latest from Liveblocks

      • Customers

        The teams Liveblocks empowers

      • Changelog

        Weekly product updates

      • Security

        Our approach to security

      • About

        The story and team behind Liveblocks

  • Docs
  • Pricing
  • Ready-made features
    • AI Copilots
    • Comments
    • Multiplayer Editing
    • Notifications
    • Presence
    Platform
    • Monitoring Dashboard
    • Realtime Infrastructure
    Solutions
    • People platforms
    • Sales tools
    • Startups
    Use cases
    • Multiplayer forms
    • Multiplayer text editor
    • Multiplayer creative tools
    • Multiplayer whiteboard
    • Comments
    • Sharing and permissions
    • Document browsing
  • Resources
    • Documentation
    • Examples
    • React components
    • DevTools
    • Next.js Starter Kit
    • Tutorial
    • Guides
    • Release notes
    Technologies
    • Next.js
    • React
    • JavaScript
    • Redux
    • Zustand
    • Yjs
    • Tiptap
    • BlockNote
    • Slate
    • Lexical
    • Quill
    • Monaco
    • CodeMirror
  • Company
    • Pricing
    • Blog
    • Customers
    • Changelog
    • About
    • Contact us
    • Careers
    • Terms of service
    • Privacy policy
    • DPA
    • Security
    • Trust center
    • Subprocessors
  • HomepageSystem status
    • Github
    • Discord
    • X
    • LinkedIn
    • YouTube
    © 2025 Liveblocks Inc.
Blog/Engineering

How to add a live avatar stack to your product with React, Firebase, and Liveblocks

Learn how you can create and add a live avatar stack to your product using React, Firebase, and Liveblocks.

on November 10th, 2021
How to add a live avatar stack to your product with React, Firebase, and Liveblocks
November 10th, 2021·7 min read
Share article

Aim

This tutorial aims to guide you on how you can create and add a live avatar stack to your product using React, Firebase, and Liveblocks. By the end of this tutorial, you should have a solid understanding of:

  • What a live avatar stack is
  • What Liveblocks is
  • How to install and connect to Liveblocks
  • How to use Firebase in Liveblocks for authentication
  • A few Liveblocks React hooks such as useOthers() and useSelf()

Prerequisites

In this guide, we assume that you already have a decent understanding of:

  • React and React Hooks,
  • Firebase and Firebase functions,
  • Javascript Async functions and Higher order functions such as array map() function.
  • Basic Node.js and npm for you to follow along easily.

Also, you need to create a Liveblocks account, sign in to your dashboard and retrieve your API key (secret key) which will be used in this tutorial.

What a live avatar stack is

A live avatar is a pictorial representation of a collaborator working in a virtual space. Applications like Figma and Dropbox use live avatars to represent active users. When the user enters the virtual space, an avatar is created to indicate the user’s presence, and also when the user leaves, the avatar is removed or dimmed to indicate the user’s absence. This helps collaborators to work as though they were in a physical room and can see who is present or not. An avatar stack is a group of avatars and here’s an image of what a typical avatar stack looks like:

Illustration of an avatar stack

Add Liveblocks to your project

To add Liveblocks to your React project, you first need to install Liveblocks packages into your project. To do that please run the following command:

$npm install @liveblocks/client @liveblocks/react

@liveblocks/client lets you connect to Liveblocks servers. @liveblocks/react contains react utilities to make it easier to consume @liveblocks/client.

Connect to Liveblocks server

Next, you need to connect to Liveblocks server using the LiveblocksProvider component in the root of your project (let’s say index.js file) and pass in client as a prop to this component. Remember this makes Liveblocks hooks available to all of your components wrapped in the LiveblocksProvider component. This is a typical example of what your root file (say index.js file) should look like:

import React from "react";import ReactDOM from "react-dom";import "./index.css";import App from "./App";
import { createClient } from "@liveblocks/client";import { LiveblocksProvider } from "@liveblocks/react";
import firebase from "firebase";import "firebase/functions";
firebase.initializeApp({ /* Firebase config */});
// We will be creating this auth endpoint function later in the tutorialconst auth = firebase.functions().httpsCallable("auth");
// Create a Liveblocks clientconst client = createClient({ authEndpoint: async (room) => (await auth({ room })).data,});
ReactDOM.render( <React.StrictMode> <LiveblocksProvider client={client}> <App /> </LiveblocksProvider> </React.StrictMode>, document.getElementById("root"));

Connect to Liveblocks room

Remember a room (the virtual space) where users collaborate? The next step is to connect to this room and to do this, we use the RoomProvider in our App.js component and set a "live-avatars" ID like so:

import React from "react";import { RoomProvider } from "@liveblocks/react";import AvatarStack from "./AvatarStack.js";
export default function App() { return ( <RoomProvider id="live-avatars"> {/* We'll be creating this AvatarStack component later in the tutorial */} <AvatarStack /> </RoomProvider> );}

Set-up authentication endpoint using Firebase

Remember you can make use of your Liveblocks public key or an authentication endpoint to create a client using the createClient function. We will be creating an authEndpoint using Firebase. We assume that you have set up your Firebase config and added Firebase to your project. Users can only interact with rooms they have access to. You can control permission access from an http endpoint by creating a Firebase function. To do that, let’s first install @liveblocks/node package in your Firebase functions project.

$npm install @liveblocks/node

Next, create a new Firebase callable function (let’s say auth) as described below. This is where you have to implement your security and define if the current user has access to a specific room. Don’t forget to replace sk_prod_xxxxxxxxxxxxxxxxxxxx with your API key.

const functions = require("firebase-functions"); const { authorize } = require("@liveblocks/node");
exports.auth = functions.https.onCall((data, context) => { /* * Implement your own security here, use the conditional checks below as a guide. * * It's your responsibility to ensure that the caller of this endpoint * is a valid user by validating the cookies or authentication headers * and that it has access to the requested room. */
//check if user is authenticated if (!context.auth) { // Throwing an HttpsError so that the client gets the error details. throw new functions.https.HttpsError('The function must be called while authenticated.'); }
//check if user has access to the room if (room === "live-avatars") { // Authentication/user information is automatically added to the request. const name = context.auth.token.name || null; const picture = context.auth.token.picture || null;
return authorize({ room: data.room, secret: "sk_prod_xxxxxxxxxxxxxxxxxxxxxxxx" //pass in your Liveblocks secret here user: {name, picture} //this is where we get the name and picture of users for our avatars }).then((authResult) => { if (authResult.status !== 200) { throw new functions.https.HttpsError(authResult.status, authResult.body); } return JSON.parse(authResult.body); }); } });

We’ve successfully set up our Firebase authentication endpoint!

Create a live avatar stack UI

Here’s the representation of what our avatar stack structure would look like:

Illustration of an avatar stack

Avatar component

This is what our Avatar.js component should look like:

import React from "react";import styles from "./Avatar.module.css";
export default function Avatar({ picture, name }) { return ( <div className={styles.avatar}> <img src={picture} alt={name} height={32} width={32} className={styles.avatar__picture} /> </div> );}

And here is the Avatar.module.css file to go alongside with it:

.avatar {  width: 32px;  height: 32px;  display: flex;  justify-content: center;  align-items: center;  border-width: 4px;  border-radius: 32px;  border-color: #ffffff;  background-color: #cfd3da;}
.avatar_picture { border-radius: 32px;}

AvatarStack component

This is what our AvatarStack.js component should look like:

import { useOthers, useSelf } from "@liveblocks/react";import React from "react";import Avatar from "./Avatar.js";import styles from "./AvatarStack.module.css";
export default function AvatarStack() { const users = useOthers().toArray(); //returns all users in the room const currentUser = useSelf(); //returns current user in the room const hasMoreUsers = users.length > 3;
return ( <div className={styles.avatar_stack}> <div className={styles.avatar_stack__others}> {users.slice(0, 3).map(({ connectionId, user }) => { return ( <Avatar key={connectionId} picture={user.picture} name={user.name} /> ); })} {hasMoreUsers && ( <div className={styles.avatar_more}>+{users.length - 3}</div> )} </div>
{currentUser && <Avatar picture={currentUser.user.picture} name="You" />} </div> );}

And here is the AvatarStack.module.css file to go alongside with it:

.avatar_stack {  display: flex;  flex-direction: row;}
.avatar_stack > * { margin-left: -8px;}
.avatar_more { width: 32px; height: 32px; display: flex; justify-content: center; align-items: center; border-width: 4px; border-radius: 32px; border-color: #ffffff; background-color: #cfd3da; color: #000000;}

Conclusion

And there you have it! Your AvatarStack component is available to be imported and used however and wherever you wish to use it in your product.

Liveblocks makes it easy to implement online/virtual presence to improve collaboration between team members. However, a live avatar stack isn’t the only presence UI pattern you can build with Liveblocks, you can also build things like live cursors, live selection, and more. Thank you for your time!

How to guides

Ready to get started?

Join thousands of companies using Liveblocks ready‑made collaborative features to drive growth in their products.

Book a demo

Related blog posts

  • Why we built our AI agents on WebSockets instead of HTTP

    Why we built our AI agents on WebSockets instead of HTTP

    Picture of Jonathan Rowny
    Picture of Nimesh Nayaju
    September 29th
    Engineering
  • What's the best vector database for building AI products?

    What's the best vector database for building AI products?

    Picture of Jonathan Rowny
    September 15th
    Engineering
  • We’ve open-sourced our customizable React emoji picker

    We’ve open-sourced our customizable React emoji picker

    Picture of Chris Nicholas
    Picture of Marc Bouchenoire
    Picture of Pierre Le Vaillant
    March 20th
    Engineering