Skip to content
Finowl

Next.js · Gender prediction

Suggest gender from names in Next.js server actions

This server action, suggestGender, prefills an optional field during onboarding. It trims the first name, adds an ISO 3166-1 alpha-2 country code when your form or profile has one, and calls /v1/gender/name. The result is returned as a discriminated union, so the Client Component can switch on kind: suggested shows a preselected but editable option, ask leaves the field empty, and retry waits before asking again.

When result_status is unknown, gender is null and the action returns the reason, which could be not_found, ambiguous or insufficient_evidence. That answer has already been charged, so the code does not retry it. Errors other than rate limits also fall back to ask. The prediction is a statistical estimate of how a name is typically used, so the person's own selection always replaces it.

Steps

  1. 1

    Add lib/finowl.ts and set FINOWL_API_KEY in your server environment.

  2. 2

    Create app/onboarding/actions.ts with the suggestGender action.

  3. 3

    Call it from your onboarding Client Component when the first name field loses focus.

  4. 4

    Render the suggestion as an editable choice that includes a prefer-not-to-say option.

  5. 5

    Save only the value the user confirms, never the raw prediction on its own.

Install
npm install server-only
Suggest gender from names in Next.js server actions
// app/onboarding/actions.ts
"use server";

import { finowl, FinowlError } from "@/lib/finowl";

type Prediction = {
  result_status: "identified" | "unknown";
  gender: string | null;
  confidence: number | null;
  source: string | null;
  reason: "not_found" | "no_name_candidate" | "ambiguous" | "insufficient_evidence" | null;
};

export type Suggestion =
  | { kind: "suggested"; gender: string; confidence: number | null }
  | { kind: "ask"; reason: string | null } // show an empty, optional field
  | { kind: "retry"; afterSeconds: number | null };

// Prefills an optional, editable field. The user's own choice always wins.
export async function suggestGender(firstName: string, country?: string): Promise<Suggestion> {
  const name = firstName.trim().slice(0, 254);
  if (!name) return { kind: "ask", reason: "no_name_candidate" };

  try {
    const { data } = await finowl<{ data: Prediction }>(
      "/v1/gender/name",
      country ? { name, country } : { name },
    );
    if (data.result_status === "unknown" || !data.gender) {
      return { kind: "ask", reason: data.reason }; // normal, billed result: don't retry
    }
    return { kind: "suggested", gender: data.gender, confidence: data.confidence };
  } catch (err) {
    if (!(err instanceof FinowlError)) throw err;
    if (err.status === 429) return { kind: "retry", afterSeconds: err.retryAfter };
    if (err.status === 400) return { kind: "ask", reason: "invalid_input" }; // e.g. bad country code
    if (err.status === 401) console.error("Finowl rejected FINOWL_API_KEY");
    return { kind: "ask", reason: null };
  }
}

IN PRODUCTION

Production tips

  • Call the action once per name rather than on each keystroke. Every lookup, including an unknown result, costs a credit, and a blur event is a natural moment to ask.

  • Mention name-based gender estimation in your privacy notice and in a short hint near the field, so people understand why a value was suggested and know they can change it.

  • Skip the AI options here. ai_mode always and forceToGenderize cost 3 credits each, and the default fallback mode already consults AI when the dataset has no answer.

Each lookup costs 1 credit (3 when it requests AI), with 100 free credits every month. See pricing and error codes.

A FEW GOOD QUESTIONS

Common questions

Suggest gender from names in Next.js server actions

Grab an API key, paste the example and run it. 100 free credits every month.