Unprofane

Firebase username check.

A Cloud Function on profile writes that clears a bad username and records why.

Runs in a Cloud Function. Every name is checked with context: "username" and the teen policy; change the policy to suit the audience. Replace the key.

// functions/src/index.ts: Cloud Function on profile writes
import { onDocumentWritten } from 'firebase-functions/v2/firestore';
import { Unprofane } from '@unprofane/sdk';
const unprofane = new Unprofane(process.env.UNPROFANE_API_KEY!);

/** Returns the reason a username cannot be shown, or null when it can. */
export async function usernameProblem(username: string): Promise<string | null> {
  const r = await unprofane.check({ text: username, context: 'username', policy: 'teen' });
  if (r.allowed) return null;
  return r.matches[0]?.category === 'reserved'
    ? 'That name is reserved.'
    : 'Pick a different username.';
}

export const guardUsername = onDocumentWritten('profiles/{uid}', async (event) => {
  const after = event.data?.after.data();
  if (!after?.username) return;
  const problem = await usernameProblem(after.username);
  if (problem) await event.data!.after.ref.update({ username: null, usernameProblem: problem });
});

Notes

The client reads `usernameProblem` back and asks again. For a synchronous answer, call the same function over HTTPS before the write.

What the response holds, and how to read a reserved name apart from a profane one, is in the API reference. The other recipes are on the username page.