Firebase

Turn Firestore document changes into qualification gate events — server-authoritative, no client instrumentation

If your app runs on Firebase, the moments that should validate a referral — an order document written, a profile marked complete, a subscription flipped to active — already happen in Firestore. Forward those document changes to Invitebase from a Cloud Function and they become qualification gate conditions, with no client-side tracking and no way for a tampered client to fake progress.

Like the Supabase recipe, this is not a Connect a source connector — it's a small Cloud Function you own that maps a document change to POST /v1/events. About twenty lines, shown below in full.

When to use this vs the SDK

You needUse
Gate on state that lives in FirestoreThis recipe — server-authoritative, tamper-proof
Referral links, deferred deep linking, invite/status UIThe Invitebase SDK — attribution still needs the client
Purchase/subscription gatesRevenueCat, Adapty, or Stripe Billing — richer subscription semantics
Your backend is Supabase, not FirebaseSupabase — the same recipe on Postgres

Most apps run the SDK for attribution and sharing, and forward Firestore changes for gates. Both event streams drive gate progress identically.

Forward a document change

The example gates on a completed order: a document created under orders/{orderId} becomes an order_completed event.

Write a 2nd-gen Cloud Function that maps the document to an Invitebase event:

functions/src/invitebase-forward.ts
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { defineSecret } from "firebase-functions/params";

const INVITEBASE_SECRET_KEY = defineSecret("INVITEBASE_SECRET_KEY");

export const forwardOrderToInvitebase = onDocumentCreated(
  {
    document: "orders/{orderId}",
    secrets: [INVITEBASE_SECRET_KEY],
    // Retry transient failures; the idempotency key below makes those retries safe.
    retry: true,
  },
  async (event) => {
    const order = event.data?.data();
    if (!order) return;

    const res = await fetch("https://api.invitebase.com/v1/events", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${INVITEBASE_SECRET_KEY.value()}`,
        "Content-Type": "application/json",
        // one key per document — retried triggers never double-count
        "Idempotency-Key": `orders-created-${event.params.orderId}`,
      },
      body: JSON.stringify({
        name: "order_completed",
        referred_user_id: order.userId,
        properties: { value: order.totalCents },
      }),
    });
    if (!res.ok) throw new Error(`invitebase: ${res.status}`);
  },
);

referred_user_id must be the same user ID you pass to the SDK's identify() — with Firebase Auth that's usually the auth UID already stored on your documents. Events for users who aren't part of an open referral are accepted and count for nothing, so you don't need to filter to referred users yourself.

Set your secret key and deploy:

firebase functions:secrets:set INVITEBASE_SECRET_KEY
firebase deploy --only functions:forwardOrderToInvitebase

Write a test document. The event appears in Developer tools → Events within seconds with source: api, and order_completed now populates the dropdowns in the gate builder — add a condition on it like any other event.

Patterns that work well

  • Gate on transitions, not states. Use onDocumentUpdated and compare event.data.before to event.data.after, forwarding only the transition you care about (before.status !== 'complete' && after.status === 'complete') — with the transition baked into the idempotency key.
  • Sum toward a target. Send a value property (minutes, cents, items) and the gate builder can sum it toward a target — see gate examples.
  • Throw on failure. Firestore triggers retry when the function errors (enable retries on the function), and the idempotency key makes retries safe — so a transient network blip never loses an event.

Environments

Firebase projects have no test/live concept, so bind each project to a mode: your dev/staging Firebase project's function gets a test-mode secret key, production gets live. Test-mode events light up the same gate progress panels so you can rehearse the whole flow before launch.

Troubleshooting

  • Events arrive but gates never progress — the forwarded ID doesn't match the referred user's identified ID. Inspect the event in the event log and compare it to the referral's participant.
  • Nothing arriving — check the function's logs (firebase functions:log or Cloud Logging). The usual suspects: the secret wasn't set in this project, or the trigger path doesn't match your collection.
  • Duplicates in the event log — expected if the trigger retried; deliveries with the same Idempotency-Key never double-count toward a gate.

What's next

On this page