Skip to main content

Demografix Python SDK

Predict gender, age, and nationality from names. The Python SDK covers all three Demografix APIs — genderize.io (gender), agify.io (age), and nationalize.io (nationality) — with single-name lookups and batches of up to 100 names per request. Synchronous and asynchronous clients share the same methods and models.

PyPI CI License: MIT

Install

pip install demografix

The SDK requires Python 3.10 or newer. The asynchronous client uses httpx.

Quickstart

Construct a client, run a list of names through a batch call, read the predictions, and read the quota.

from collections import Counter
from demografix import Demografix

client = Demografix(api_key="YOUR_API_KEY")

names = ["michael", "matthew", "jane", "sofia", "lars"]

batch = client.genderize_batch(names)

split = Counter(r.gender or "unknown" for r in batch.results)
print(split)                      # Counter({'male': 3, 'female': 2})
print(batch.quota.remaining)      # 24987

Async client

AsyncDemografix mirrors the synchronous API with native async HTTP. Use one client across requests so its connection pool can be reused, and close it with async with or aclose().

import asyncio
from collections import Counter
from demografix import AsyncDemografix

async def main():
    names = ["michael", "matthew", "jane", "sofia", "lars"]

    async with AsyncDemografix(api_key="YOUR_API_KEY") as client:
        genders, ages, nationalities = await asyncio.gather(
            client.genderize_batch(names),
            client.agify_batch(names),
            client.nationalize_batch(names),
        )

    split = Counter(r.gender or "unknown" for r in genders.results)
    print(split)
    print(nationalities.quota.remaining)

asyncio.run(main())

Task cancellation propagates normally. Network failures and timeouts raise TransportError, matching the synchronous client.

genderize

Predict gender from names. A single call returns the prediction fields plus a quota.

result = client.genderize("peter")
result.gender          # "male", "female", or None
result.probability     # 1.0
result.count           # 1352696
result.quota.remaining # 24987

The batch form reduces a list to a gender split.

batch = client.genderize_batch(["michael", "matthew", "jane"])
gender_mix = Counter(r.gender or "unknown" for r in batch.results)

gender is None when no match is found, with probability 0.0 and count 0. That is a successful response, not an error.

agify

Predict age from names. Aggregate a batch into an age distribution.

result = client.agify("michael")
result.age             # 57 or None
result.count           # 311558

batch = client.agify_batch(["michael", "matthew", "jane"])
ages = [r.age for r in batch.results if r.age is not None]
average_age = sum(ages) / len(ages)

age is an integer or None.

nationalize

Predict nationality from names. Each prediction carries up to five candidate countries in descending probability.

result = client.nationalize("nguyen")
result.country[0].country_id      # "VN"
result.country[0].probability     # 0.891132

batch = client.nationalize_batch(["nguyen", "schmidt", "rossi"])
top_countries = Counter(
    r.country[0].country_id for r in batch.results if r.country
)

country is an empty list when no match is found.

Batch limit

Each batch accepts at most 100 names. A batch of more than 100 raises ValidationError before any request goes out. Chunk a longer list and aggregate across the chunks.

def chunked(items, size=100):
    for i in range(0, len(items), size):
        yield items[i : i + size]

split = Counter()
for chunk in chunked(roster):
    batch = client.genderize_batch(chunk)
    split.update(r.gender or "unknown" for r in batch.results)

country_id

genderize and agify accept an optional country_id (ISO 3166-1 alpha-2) to scope the prediction to one country. Input is case-insensitive; the response echoes it uppercase on every prediction. nationalize has no such parameter.

result = client.genderize("kim", country_id="us")
result.country_id      # "US"

# Scope a whole list, then aggregate.
batch = client.agify_batch(["kim", "andrea", "jan"], country_id="us")
ages = [r.age for r in batch.results if r.age is not None]
batch.results[0].country_id   # "US", echoed uppercase on each prediction

Scoping changes the prediction: andrea reads mostly female in the United States and mostly male in Italy. When the request sends no country_id, the field is None.

Quota

Every result and every raised error carries a quota read from the response headers. Quota is never cached on the client; read it from the returned value.

Field Meaning
limit names allowed in the current window
remaining names left in the current window
reset seconds until the window resets
batch = client.genderize_batch(["michael", "matthew"])
batch.quota.remaining

Errors

Non-2xx responses raise a typed exception. Transport failures raise TransportError. Every exception subclasses DemografixError and carries status, message, and quota (when the response included headers).

Exception Status Cause
AuthError 401 invalid or missing API key
SubscriptionError 402 expired freebie or inactive subscription
ValidationError 422 bad parameter, or a batch over 100 names (raised client-side)
RateLimitError 429 window exhausted; quota is always populated
DemografixError other non-2xx base class for the hierarchy
TransportError none network error, timeout, or non-JSON body

A RateLimitError carries quota, so reset tells you how long to wait before retrying.

import time
from demografix import Demografix, RateLimitError

client = Demografix(api_key="YOUR_API_KEY")
names = ["michael", "matthew", "jane"]

while True:
    try:
        batch = client.genderize_batch(names)
        break
    except RateLimitError as exc:
        time.sleep(exc.quota.reset)

Methods

Method Returns country_id
genderize(name, country_id=None) GenderizeResult yes
genderize_batch(names, country_id=None) Batch of GenderizePrediction yes
agify(name, country_id=None) AgifyResult yes
agify_batch(names, country_id=None) Batch of AgifyPrediction yes
nationalize(name) NationalizeResult no
nationalize_batch(names) Batch of NationalizePrediction no

A *Result exposes the prediction fields directly plus a quota. A Batch exposes results plus one quota for the whole response. Both Demografix and AsyncDemografix expose the methods above; await methods on AsyncDemografix. Each constructor takes api_key and an optional timeout=10.0. The host URLs and the User-Agent are fixed constants, not options.

AsyncDemografix supports async with and aclose() to close its connection pool. The synchronous client retains its existing lifecycle and requires no explicit cleanup.

API keys

An API key is required. Creating one is free and includes 2,500 names per month.

Quota counts names, not requests. A single-name call costs 1. A batch of 100 names costs 100. The free tier therefore covers 2,500 names in a month however they are split across calls.

Generate a key in your dashboard at genderize.io, agify.io, or nationalize.io. One key works across all three services. Full reference: genderize.io/documentation/api.

License

MIT. See LICENSE.

Release files for demografix 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for demografix 0.3.0
File Size Uploaded
demografix-0.3.0.tar.gz 15.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for demografix 0.3.0
File Interpreter ABI Platform
demografix-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.9 kB

Release files / demografix-0.3.0.tar.gz

Download URL demografix-0.3.0.tar.gz
Size 15.5 kB
Tags Source
SHA-256 checksum
How to use checksums
49d903dd97f2101ae2e58978f0fc4824c6244273f01e9b4972eab26823f11a1b
BLAKE2b-256 checksum
How to use checksums
2fcf977a63cb4448e5b96ad416c1fa32affd6ad8a07ff598f46239eef52e7d3a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / demografix-0.3.0-py3-none-any.whl

Download URL demografix-0.3.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c99e606c7955efe55eb8bd688b82f7a2474e4c5c0f6586c6b8fb83f5d4ea90f0
BLAKE2b-256 checksum
How to use checksums
86549eb4aa3f34de2584fe6471a75377a97f93351109c2be8c8e7cc110c6db21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page