demografix (Ruby)
Run demographic analysis over names — predicted gender, age, and nationality — from one Ruby client. The gem covers genderize.io, agify.io, and nationalize.io.
Install
Add the gem to your Gemfile:
gem "demografix"
Then run bundle install. To install directly:
gem install demografix
The client uses the Ruby standard library (net/http and json) and has no runtime dependencies. It requires Ruby 3.2 or later.
Authentication
An API key is required. Creating one is free and includes 2,500 requests per month. Generate a key in your dashboard at genderize.io, agify.io, or nationalize.io. One key works across all three services.
Quickstart
Construct a client, run a batch over a list of names, read the predictions, and read the remaining quota.
require "demografix"
client = Demografix::Client.new(api_key: ENV.fetch("DEMOGRAFIX_API_KEY"))
names = %w[michael matthew jane emily peter lois]
ages = client.agify_batch(names)
# Aggregate the predictions into an age distribution for the list.
known = ages.results.map(&:age).compact
average_age = known.sum.to_f / known.length
ages.quota.remaining # => 24987
Each call returns prediction fields plus a quota. Batch calls return results (one prediction per input
name, in input order) plus one quota for the response. Aggregate the results into a distribution.
genderize
Predict gender from a name.
result = client.genderize("peter")
result.gender # => "male"
result.probability # => 1.0
result.count # => 1352696
Batch a list and reduce it to a gender split:
batch = client.genderize_batch(%w[peter lois meg chris])
split = batch.results.each_with_object(Hash.new(0)) do |pred, counts|
counts[pred.gender || "unknown"] += 1
end
# => { "male" => 2, "female" => 2 }
gender is "male", "female", or nil. A name with no match returns nil gender, 0.0 probability,
and 0 count. That is a successful response, not an error.
agify
Predict age from a name.
result = client.agify("michael")
result.age # => 57
result.count # => 311558
Batch a list and reduce it to an age distribution:
batch = client.agify_batch(%w[michael matthew jane])
ages = batch.results.map(&:age).compact
buckets = ages.group_by { |age| (age / 10) * 10 }
# => { 50 => [57], 40 => [48], ... }
age is an integer or nil. A name with no match returns nil age and 0 count.
nationalize
Predict nationality from a name.
result = client.nationalize("nguyen")
result.country.first.country_id # => "VN"
result.country.first.probability # => 0.891132
Batch a list and reduce it to a nationality mix:
batch = client.nationalize_batch(%w[nguyen schmidt rossi])
mix = batch.results.each_with_object(Hash.new(0)) do |pred, counts|
top = pred.country.first
counts[top ? top.country_id : "unknown"] += 1
end
# => { "VN" => 1, "DE" => 1, "IT" => 1 }
country holds up to five candidates in descending probability order. A name with no match returns an empty
country array.
country_id
genderize and agify accept an optional country_id (ISO 3166-1 alpha-2) to scope the prediction to a
country. nationalize does not accept it.
result = client.genderize("kim", country_id: "US")
result.country_id # => "US"
result.gender # => "female"
client.agify_batch(%w[andrea andrea], country_id: "IT")
The value is echoed back uppercase in country_id on each prediction. When the request sends no
country_id, the field is nil.
Quota
Every result and every raised error carries a quota read from the response rate-limit headers:
| Field | Meaning |
|---|---|
limit |
names allowed in the current window |
remaining |
names left in the current window |
reset |
seconds until the window resets |
result = client.genderize("peter")
result.quota.limit # => 25000
result.quota.remaining # => 24987
result.quota.reset # => 1314000
Read quota off the returned value or a raised error. The client does not cache it.
Errors
Every error subclasses Demografix::Error and carries status, message, and quota (when the response
included rate-limit headers).
| Error | Raised on |
|---|---|
Demografix::AuthError |
401, invalid or missing API key |
Demografix::SubscriptionError |
402, subscription not active |
Demografix::ValidationError |
422, invalid parameters; also client-side for a batch over 10 names |
Demografix::RateLimitError |
429, request limit reached (quota always populated) |
Demografix::TransportError |
network failure, timeout, or non-JSON body |
Demografix::Error |
any other non-2xx status |
A batch of more than 10 names raises ValidationError before any HTTP call is made.
On a RateLimitError, read quota.reset for the seconds to wait before retrying:
begin
client.genderize_batch(names)
rescue Demografix::RateLimitError => e
sleep(e.quota.reset)
retry
end
Methods
| Method | Returns | country_id |
|---|---|---|
genderize(name, country_id:) |
GenderizeResult |
yes |
genderize_batch(names, country_id:) |
Batch of GenderizePrediction |
yes |
agify(name, country_id:) |
AgifyResult |
yes |
agify_batch(names, country_id:) |
Batch of AgifyPrediction |
yes |
nationalize(name) |
NationalizeResult |
no |
nationalize_batch(names) |
Batch of NationalizePrediction |
no |
Demografix::Client.new requires api_key: and accepts timeout: (optional, default 10 seconds). The
host URLs and the User-Agent are fixed constants, not options.
Full API reference: https://genderize.io/documentation/api