Setup

Set up student access

Room Sharing lets your students read your live captions on their own devices. It runs on a free Google Firebase project that you create and control, so your class's data stays private and the whole thing stays free. You only do this once.

About 10 minutes · No coding · Browser only
1

Create a Firebase project

Go to console.firebase.google.com and sign in with a Google account (your personal one is fine).

Click Create a project and give it any name, such as Classroom Captions.

Tip: when it asks about Google Analytics, switch it off. It isn't needed. Then finish creating the project.
2

Turn on anonymous sign-in

This lets student devices connect without anyone logging in or creating an account.

  • In the left sidebar, under Product categories, click Security.
  • Click Authentication, then Get started.
  • Choose Anonymous from the list of sign-in providers.
  • Toggle it to Enable, then click Save.
Can't find it? If Authentication isn't under Security, type Authentication into the Search for products box at the top of the sidebar.
3

Create the Realtime Database

  • In the left sidebar, under Product categories, click Databases & Storage.
  • Click Realtime Database, then Create Database.
  • Pick the location closest to you and continue.
  • When asked about security rules, start in locked mode. You'll paste the real rules next.
Important: choose Realtime Database, not "Firestore Database" (also called "Cloud Firestore"). They sit near each other, and this extension uses Realtime Database.
4

Paste in the security rules

These rules keep students from injecting fake captions or seeing each other's data. They run on Google's servers, so they can't be bypassed.

  • On the Realtime Database page, click the Rules tab.
  • Select everything in the box and delete it.
  • Copy the rules below and paste them in.
  • Click Publish.
Security rules, paste all of this
{
  "rules": {
    ".read": false,
    ".write": false,

    "rooms": {
      "$roomCode": {
        ".read": "data.child('active').val() === true && data.child('expiresAt').val() > now",
        "ownerUid":  { ".validate": "newData.isString() && newData.val().length > 0" },
        "createdAt": { ".validate": "newData.isNumber()" },
        "expiresAt": { ".validate": "newData.isNumber()" },
        "active":    { ".validate": "newData.isBoolean()" },
        "type":      { ".validate": "newData.isString() && newData.val() === 'main'" },
        ".write": "(!data.exists() && auth != null && newData.child('ownerUid').val() === auth.uid && newData.child('expiresAt').val() <= (now + 28800001)) || (data.exists() && data.child('ownerUid').val() === auth.uid)",
        "captions": {
          ".read": "data.parent().child('active').val() === true && data.parent().child('expiresAt').val() > now",
          "$pushId": {
            ".write": "auth != null && data.parent().parent().child('ownerUid').val() === auth.uid",
            ".validate": "newData.hasChildren(['text','timestamp'])",
            "text":      { ".validate": "newData.isString() && newData.val().length <= 5000" },
            "timestamp": { ".validate": "newData.isNumber()" },
            "translations": { ".validate": "newData.hasChildren() || newData.val() === null" },
            "$other": { ".validate": true }
          }
        },
        "connections": {
          "$connUid": {
            ".write": "auth != null && $connUid === auth.uid && data.parent().parent().child('active').val() === true",
            ".validate": "newData.hasChild('lastSeen')",
            "joinedAt": { ".validate": "newData.isNumber()" },
            "lastSeen": { ".validate": "newData.isNumber()" },
            "$other": { ".validate": false }
          }
        },
        "$other": { ".validate": false }
      }
    },

    "accommodationRooms": {
      "$accommodationCode": {
        ".read": "data.child('active').val() === true && data.child('expiresAt').val() > now",
        "ownerUid":  { ".validate": "newData.isString() && newData.val().length > 0" },
        "createdAt": { ".validate": "newData.isNumber()" },
        "expiresAt": { ".validate": "newData.isNumber()" },
        "active":    { ".validate": "newData.isBoolean()" },
        "type":      { ".validate": "newData.isString() && newData.val() === 'accommodation'" },
        ".write": "(!data.exists() && auth != null && newData.child('ownerUid').val() === auth.uid && newData.child('expiresAt').val() <= (now + 28800001)) || (data.exists() && data.child('ownerUid').val() === auth.uid)",
        "connections": {
          "$connUid": {
            ".write": "auth != null && $connUid === auth.uid && data.parent().parent().child('active').val() === true",
            ".validate": "newData.hasChild('lastSeen')",
            "joinedAt": { ".validate": "newData.isNumber()" },
            "lastSeen": { ".validate": "newData.isNumber()" },
            "$other": { ".validate": false }
          }
        },
        "$other": { ".validate": false }
      }
    }
  }
}
5

Get your configuration

  • Near the top of the left sidebar, click Settings (the gear), then General.
  • Scroll to Your apps and click the web icon </> (angle brackets, not the iOS or Android icons) to register a web app.
  • Give it any nickname and click Register app. Leave Also set up Firebase Hosting unchecked.

Firebase shows an Add Firebase SDK screen. Ignore the npm and <script> options. Just find the block that starts with const firebaseConfig:

Example, yours will have real values
const firebaseConfig = {
  apiKey: "AIzaSy...",
  authDomain: "your-project.firebaseapp.com",
  databaseURL: "https://your-project-default-rtdb.firebaseio.com",
  projectId: "your-project",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "1234567890",
  appId: "1:1234:web:abcd"
};
Tip: copy only what's inside the curly braces { } (braces included). Don't include const firebaseConfig =, and don't copy the semicolon after the closing brace.
6

Paste it into the extension

  • Open the extension's Settings & styling page and find the Room Sharing section.
  • Paste your configuration into the Firebase configuration box and click Save settings.

The extension checks your configuration when you save and tells you if anything looks off. You won't need to touch Firebase again.

7

Name your class and share the code

In the same Settings page, open Share with your students and give your class a name students will recognize, like Mr. Leatherwood, Chemistry. The name travels with your join code, so students who have several teachers can tell your class apart in their list.

Then copy your join code (or the styled invite for Canvas / Classroom) and post it where your students will see it. It's the same code all year.

That's it

Start captions and your students who joined with your code will see them live, each in the language they pick. Need to set up AI Mode too? See Connect your OpenAI account.