Gender API for R
Add a gender column to a data frame of names from R, keep the probability and sample size behind every row, and record the data version your analysis was run against.
100 free credits every day. No card.
Install and make the first request
The R client is installed from GitHub and needs R 4.1 or later, with httr2 and jsonlite as its only dependencies. Keep the API key in an environment variable, for example in .Renviron, so that it never ends up in a script or notebook you share with co-authors or commit to a repository.
A result is a list rather than a single label. gender is "male", "female" or NULL; probability is an integer from 0 to 100; sample_size is the number of recorded people the answer rests on; confidence and source say how it was reached. Read them together. A NULL gender is a successful answer that the evidence was insufficient, not an error, and it should become NA in your data rather than a guessed category.
Pass the country as an ISO two-letter code whenever your data has one. Andrea is a man in Italy and a woman in Germany, and without a country hint the API returns the globally dominant reading, which will be wrong for a predictable share of a multinational sample.
remotes::install_github("anpekesen/namegender-r", ref = "v0.3.0")
library(namegender)
client <- namegender(Sys.getenv("NAMEGENDER_API_KEY"))
result <- ng_name(client, "Andrea", country = "IT")
result$gender
result$probability
result$sample_size
Copy failed. Select and copy the text.
A whole data frame, one hundred names at a time
ng_bulk() sends up to 100 names in one request and returns the results as a data frame in the order sent, so for a small table it can be assigned straight back as a column. For anything larger, look up each distinct name once, in chunks of 100, and merge the answers back. An author list or a survey export usually repeats the same first names many times, and paying for each repetition buys nothing.
If your rows carry different countries, group the distinct names by country and send one set of chunks per country, because a bulk request takes a single country hint. Keep the country in the merge key: the same first name can have a different answer in a different market, and joining on the name alone would silently overwrite one with the other.
Keep probability and sample_size as columns next to gender instead of discarding them after the lookup. They let you set a threshold later, report how many rows fell below it, and run a sensitivity analysis without calling the API again.
names <- unique(df$first_name)
chunks <- split(names, ceiling(seq_along(names) / 100))
lookup <- do.call(rbind, lapply(chunks, function(x) {
ng_bulk(client, x)$results[, c("query", "gender", "probability", "sample_size")]
}))
df <- merge(df, lookup, by.x = "first_name", by.y = "query", all.x = TRUE)
table(df$gender, useNA = "ifany")
Copy failed. Select and copy the text.
What to write in the methods section
Inferred gender is an estimate from a name, not a record of how a person identifies, and a reviewer will ask how you handled that. State the threshold you used, the share of names that fell below it or came back unknown, and whether those rows were excluded or reported separately. Name-based inference also works less well for some regions and scripts than for others; our published benchmark gives the figures per script, including where we perform worse than other services, so you can cite the limitation instead of discovering it.
Every response carries a data_version field. Record it together with the date of the run. A later update to the underlying name data can change a small number of answers, and the version makes a re-run explainable rather than merely different.
If you only study historical cohorts in the United States, the rOpenSci gender package, which infers gender from historical records keyed by birth year and runs offline, may be the better fit, and it is free. The API is the stronger choice for contemporary, multi-country data, names written in non-Latin scripts, full names that need splitting, and email addresses or usernames rather than clean first names.
Questions
Which R versions are supported?
R 4.1 and later. The client depends only on httr2 and jsonlite.
Can I look up a column of a data frame?
Yes. Send the distinct names with ng_bulk() in chunks of 100 and merge the results back on the name, and on the country if your rows have one.
What happens to names the API does not know?
gender comes back as NULL, which becomes NA in a data frame. Keep those rows and report how many there were rather than assigning a default.
How do I make the lookup reproducible?
Store the data_version returned with the response and the date of the run, and keep probability and sample_size as columns so thresholds can be changed without calling the API again.
Related pages
Call the NameGender API from Python, send country-aware and bulk lookups, handle unknown results, and keep probability and evidence fields in your pipeline.
Upload a CSV or XLSX name list and get a gender column back, with confidence fields, automatic deduplication and the cost shown before charging.
Every name lookup returns a probability, a sample size and a confidence tier. What each one measures, how the tiers are set, and where to put your threshold.
Measured on 4,610 labelled names from 25 countries: 88% answered, 96% of answers correct, 84% end to end. Results by script, and where the errors come from.
Reading the gender field alone discards everything that says whether to believe it. What each response field means and the thresholds behind confidence.
Check it against your own list
Every number on this page is reproducible with a free key. If your data breaks it, that is the more interesting result.