Skip to content
Finowl

Gender prediction

Gender prediction from usernames, nicknames and AI mode

Predict gender from usernames and handles with forceToGenderize or ai_mode always, understand the 3-credit price, and read source ai and model_reported results.

Usernames and handles are where name-based gender prediction gets hard. A handle like jsmith_92 hides a name behind an initial, and a nickname like prenses contains no real name at all. Finowl offers two ways to bring AI into these lookups, forceToGenderize and options.ai_mode: "always", and this post explains when to use each, what they cost, and how to read the results.

Why usernames are different

A name field is usually a direct statement: the person typed their name. A username is a choice of identity, and people pick handles for all sorts of reasons. Some contain a real name (maria_g, danielcooks). Some contain an initial plus a surname (jsmith_92). Many contain no name: words, jokes, references, or strings in another language.

A dataset of how first names are used can only help when the handle contains a first name. For everything else, the only way to get an estimate is to ask a model to read the handle the way a person might. That is what AI mode is for.

Start with the plain endpoint

The username endpoint works like the name and email endpoints. With no options, single lookups use the default ai_mode: "fallback": Finowl tries the dataset first and only uses AI if the dataset has no answer.

bash
curl -X POST https://api.finowl.co/v1/gender/username \
  -H "Authorization: Bearer $FINOWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "username": "jsmith_92" }'

For handles that contain a recognizable first name, this is often all you need. For handles that do not, you will see result_status: "unknown" with a reason such as no_name_candidate.

Two ways to use AI

forceToGenderize

forceToGenderize: true is built for nicknames and handles that contain no real name. Finowl still checks the dataset first. If that does not produce an answer, AI reads the handle and estimates from it. A nickname like prenses, which is the Turkish word for "princess", has no first name for a dataset to match, but a model can recognize what the word means.

bash
curl -X POST https://api.finowl.co/v1/gender/username \
  -H "Authorization: Bearer $FINOWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "username": "prenses", "forceToGenderize": true }'

forceToGenderize cannot be combined with ai_mode: "off" or ai_mode: "always". Sending both returns 400 with code invalid_input. Requests rejected before running are free, but your code still needs to fix the request.

options.ai_mode: "always"

options.ai_mode has three values:

Value Behavior
fallback Dataset first, AI only if there is no answer (default for single lookups)
off Dataset only (default for batch items)
always Always use AI

With always, the model answers every request, even when the dataset could have. Use it when you specifically want a model reading of the input, for example when comparing approaches or when your handles are mostly nicknames.

bash
curl -X POST https://api.finowl.co/v1/gender/username \
  -H "Authorization: Bearer $FINOWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "username": "danielcooks", "options": { "ai_mode": "always" } }'

Which one to choose

  • Choose forceToGenderize when you want dataset answers wherever possible and an AI reading only for handles without a real name. This suits most username and nickname data.
  • Choose ai_mode: "always" when you want every result to come from the model.
  • Choose the default fallback, or off, when you want to avoid AI pricing and accept more unknowns.

The AI mode guide covers the full rules.

The 3-credit price

A standard gender lookup costs 1 credit. A lookup that requests AI, with ai_mode: "always" or forceToGenderize: true, costs 3 credits. The same applies to batch items: each item that requests AI is priced at 3 credits, and each row in the batch response reports its charged_credits.

That makes AI requests worth targeting rather than turning on everywhere. A practical approach:

  1. Run your list with the default mode first.
  2. Collect the items that came back unknown with reason: "no_name_candidate".
  3. Re-run only those with forceToGenderize: true.

Every account gets 100 free credits each month, used before paid credits, which is plenty to test how AI handles a sample of your own handles. For volume, prepaid packs never expire; see pricing and our guide to estimating API credit usage.

Reading AI results

When the model provides the answer, the response tells you clearly. Here is the shape of an AI result (values are illustrative):

json
{
  "data": {
    "result_status": "identified",
    "gender": "female",
    "confidence": 0.85,
    "confidence_kind": "model_reported",
    "sample_count": null,
    "name": "prenses",
    "country": null,
    "source": "ai",
    "reason": null
  }
}

source: "ai"

source tells you who answered. "dataset" means a frequency lookup; "ai" means the model. Store this field alongside the prediction so you can filter or report on AI answers separately later.

confidence_kind: "model_reported"

For dataset answers, confidence_kind is "observed_frequency": the confidence is the share of observed records with that gender, backed by sample_count records. For AI answers, it is "model_reported": the confidence is the model's own estimate. There is no count behind it, which is why sample_count is null.

Model-reported confidence is useful for ranking, but it is not directly comparable to observed frequency. A 0.85 from a model and a 0.85 from thousands of records do not mean the same thing. Set separate thresholds for each kind.

Putting it together

Here is a Python helper that reads both kinds and applies a stricter bar to AI answers:

python
import os
import requests

API = "https://api.finowl.co/v1/gender/username"
HEADERS = {"Authorization": f"Bearer {os.environ['FINOWL_API_KEY']}"}

def gender_from_handle(handle, use_ai=False):
    body = {"username": handle}
    if use_ai:
        body["forceToGenderize"] = True
    res = requests.post(API, headers=HEADERS, json=body, timeout=15)
    if res.status_code == 429:
        retry_after = res.headers.get("Retry-After")
        raise RuntimeError(f"rate limited or out of credits, retry after {retry_after}")
    res.raise_for_status()
    d = res.json()["data"]

    if d["result_status"] != "identified":
        return {"gender": None, "reason": d["reason"], "source": d["source"]}

    if d["confidence_kind"] == "model_reported":
        ok = d["confidence"] >= 0.9
    else:
        ok = d["confidence"] >= 0.8 and (d["sample_count"] or 0) >= 50
    return {"gender": d["gender"] if ok else None, "source": d["source"],
            "confidence": d["confidence"], "kind": d["confidence_kind"]}

print(gender_from_handle("prenses", use_ai=True))

A 429 can mean rate_limited (60 requests per minute per account) or quota_exceeded (not enough credits). Check the error code before retrying, and wait for Retry-After when rate limited.

Where AI on handles goes wrong

Handles are noisy, and models make mistakes. Watch for:

  • Words that are also names. A handle built around an ordinary word can look like a name to a dataset.
  • Pop culture and in-jokes. A handle referencing a character, band or meme says little about the person behind it.
  • Language and context. A word that suggests a gender in one language may not in another.
  • Handles chosen to mislead or to be neutral. Many people pick handles precisely so they do not reveal anything.

This is why unknown remains a healthy outcome, and why AI results deserve a stricter threshold. For the fundamentals, see how gender prediction from names works.

Responsible use

A prediction from a username is an even weaker signal than one from a name. It is a statistical estimate, not a statement about how a person identifies, and it will be wrong for some people.

  • Use results for aggregate analytics and low-stakes personalization only.
  • Never use them for eligibility, pricing, access or decisions with significant effects.
  • Let people state or correct their own gender, and never overwrite what they told you with a prediction.
  • Mention gender lookups in your privacy notice, since usernames and derived estimates are personal data.

More on the product is on the gender API page.

Frequently asked questions

What is the difference between forceToGenderize and ai_mode always?

forceToGenderize: true checks the dataset first and only then lets AI read a nickname or handle with no real name. ai_mode: "always" uses AI for every request. Both cost 3 credits per lookup.

Can I use forceToGenderize with ai_mode off or always?

No. Combining forceToGenderize: true with ai_mode: "off" or ai_mode: "always" returns a 400 error. Requests rejected before running are not charged.

How do I know a prediction came from AI?

AI answers have source: "ai", confidence_kind: "model_reported" and sample_count: null. Dataset answers have source: "dataset", confidence_kind: "observed_frequency" and a numeric sample_count.

Do batch requests use AI by default?

No. Batch items default to ai_mode: "off", so they use the dataset only unless you request AI for an item.

All articles