Fetch and normalize entities from Wikidata, Wikipedia and DBpedia.
- Zero runtime dependencies — built on
fetch, ESM + CommonJS, fully typed. - Batches, retries and rate-limit aware by default.
- Flattens Wikidata's deeply nested claim format into something you can read.
npm install wiki-entityRequires Node.js >= 20.19.
import { getEntities, setUserAgent } from "wiki-entity";
setUserAgent("MyApp/1.0 (https://myapp.example; contact@myapp.example)");
// by Wikipedia article title
const [europe] = await getEntities({ language: "en", titles: ["Europe"] });
// by Wikidata id, with a Wikipedia summary and resolved claim labels
const [einstein] = await getEntities({
language: "en",
ids: ["Q937"],
extract: 2,
claims: "all"
});
einstein.label; // "Albert Einstein"
einstein.extract; // "Albert Einstein was a German-born theoretical physicist…"
einstein.claims.P569.label; // "date of birth"
einstein.claims.P569.values[0].value_string; // "1879-03-14"CommonJS works too:
const { getEntities } = require("wiki-entity");Wikimedia's User-Agent policy
requires every client to identify itself. Generic agents get throttled or
blocked with HTTP 429. Set yours once at startup:
import { setUserAgent } from "wiki-entity";
setUserAgent("MyApp/1.0 (https://myapp.example; contact@myapp.example)");or via the environment:
WIKI_ENTITY_USER_AGENT="MyApp/1.0 (https://myapp.example; contact@myapp.example)"Fetches entities from Wikidata and enriches them from Wikipedia and DBpedia.
Results follow the order of the requested ids/titles; entities that do not
exist are omitted.
| Param | Type | Default | Description |
|---|---|---|---|
ids |
string[] |
— | Wikidata ids, max 500. Either this or titles is required. |
titles |
string[] |
— | Wikipedia article titles in language, max 500. |
language |
string |
"en" |
Language of titles and of the resulting label/description. |
languages |
string[] |
— | Extra languages to populate labels with. |
props |
string[] |
all | info, sitelinks, aliases, labels, descriptions, claims, datatype. |
claims |
string |
none |
none, item, property or all — how deeply to resolve claim labels. |
extract |
number |
— | Sentences of the Wikipedia lead section to fetch. |
types |
boolean | string[] |
false |
true for DBpedia ontology types, or an array of prefixes to keep (e.g. ["dbo", "schema"]). |
redirects |
boolean |
false |
Titles of Wikipedia articles that redirect to this entity. |
categories |
boolean |
false |
The article's non-hidden categories. |
wikiPageId |
boolean |
true |
Fetch the Wikipedia pageid. |
httpTimeout |
number |
15000 |
Per-request timeout in milliseconds. |
signal |
AbortSignal |
— | Cancels every underlying request. |
followEntityRedirects |
boolean |
true |
Resolve Wikidata items that were merged into another item. |
extract, redirects and categories need the entity to have a sitelink for
language, so keep sitelinks in props when you narrow it.
Note redirects and followEntityRedirects are unrelated: the first fetches
the titles of Wikipedia articles pointing at this entity, the second controls
whether a merged-away Wikidata item resolves to the item that replaced it.
Resolves Wikipedia redirect titles to the articles they point at. Only titles that really are redirects appear in the result.
await mapRedirects(["Brashov"], "ro"); // { Brashov: "Brașov" }getEntities followed by convertToSimpleEntity, in one call. Takes the same
params, plus an optional { defaultType }.
const entities = await getSimpleEntities({
language: "en",
ids: ["Q937"],
types: true,
extract: 2
});
entities[0].name; // "Albert Einstein"
entities[0].type; // SimpleEntityType.PERSONPrefer this over calling the two by hand: it takes the language from params,
so it cannot drift. Converting with a different language than you fetched with
silently mixes them — name and about come from the fetch, while
wikiPageTitle is read from the sitelinks of whichever language you passed.
Flattens a single WikiEntity into the compact shape. Use it when you already
have entities from getEntities.
For what getEntities does not cover. Everything else in the package is an
implementation detail and may change without a major release.
| Export | Purpose |
|---|---|
queryPages(options) |
Query Wikipedia articles directly — batched, continuation-safe. |
simplifyEntity(lang, raw, options?) |
Flatten a raw wbgetentities entity you fetched yourself. |
getEntityTypesByNames(names, options?) |
DBpedia ontology types for English Wikipedia titles. |
setDbpediaEndpoint / getDbpediaEndpoint |
Point type lookups at a DBpedia mirror. |
setUserAgent / getUserAgent |
The User-Agent sent with every request. |
Talks to Wikipedia only — no Wikidata lookup, no entity ids. Use it when you have article titles and want their summaries, redirects or categories.
import { queryPages } from "wiki-entity";
const { pages } = await queryPages({
lang: "en",
titles: ["Chișinău", "Italy"],
extract: 2,
followRedirects: true
});
for (const page of pages) {
console.log(page.pageid, page.title, page.extract);
}| Option | Type | Description |
|---|---|---|
lang |
string |
Wikipedia language code, e.g. "en". Required. |
titles |
string[] |
Article titles. Required; batched automatically. |
extract |
number |
Sentences of the lead section to fetch. |
redirects |
boolean |
Titles of articles redirecting to each page. |
categories |
boolean |
Each article's non-hidden categories. |
followRedirects |
boolean |
Resolve titles that are themselves redirects. |
httpTimeout |
number |
Per-request timeout in milliseconds. |
signal |
AbortSignal |
Cancels every underlying request. |
It handles the parts of the MediaWiki API that are easy to get wrong: titles are
batched (50 per request, or 20 when extract is set, since the API refuses more
intro extracts than that), and paginated continue responses are followed, so
long redirects and categories lists are not truncated at the first page.
pages is not in the order you asked for, and MediaWiki normalizes titles
and follows redirects, so the title that comes back may not be the one you sent.
Two maps tie the results back to your input:
const { pages, resolved, requestedTitleOf } = await queryPages({
lang: "en",
titles: ["Kishinev"],
categories: true,
followRedirects: true
});
pages[0].title; // "Chișinău" — the redirect target
resolved.get("Kishinev"); // { title: "Chișinău", redirected: true }
requestedTitleOf.get("Chișinău"); // "Kishinev"Earlier releases had getExtract, getExtracts and getRedirects for this.
They were thin wrappers that only ever handled one request's worth of titles:
// before // now
getExtracts({ lang, titles, sentences: 2 }); // queryPages({ lang, titles, extract: 2 })
getExtract(lang, title, 2); // queryPages({ lang, titles: [title], extract: 2 })
getRedirects(lang, title); // queryPages({ lang, titles: [title], redirects: true })getExtract returned a single object or null; the equivalent is
(await queryPages({ lang, titles: [title], extract: 2 })).pages[0] ?? null.
All errors extend WikiEntityError:
HttpError— non-2xx status, network failure or timeout.status,urlandretryabledescribe it; 429 and 5xx are retried automatically.ApiError— the request succeeded but MediaWiki reported an error (code).
Bad arguments throw a plain TypeError.
DBpedia types are best-effort enrichment: if the endpoint is unreachable,
types is simply left unset instead of failing the call.
WikiEntity is a flattened Wikidata item, plus the extras pulled from
Wikipedia and DBpedia.
type WikiEntity = {
id: string;
label?: string;
labels?: Record<string, string>;
description?: string;
descriptions?: Record<string, string>;
aliases?: string[];
sitelinks?: Record<string, string>;
claims?: Record<string, WikidataProperty>;
/** Wikipedia page id (not Wikidata's). */
pageid?: number;
extract?: string;
types?: string[];
redirects?: string[];
categories?: string[];
redirectsToId?: string;
redirectsFromId?: string;
};
type WikidataProperty = {
id: string;
label?: string;
description?: string;
values: WikidataPropertyValue[];
};
type WikidataPropertyValue = {
datatype: string;
/** Scalar for simple datatypes, the raw object for time/quantity/coordinates. */
value: string | number | object;
/** Readable rendering of a structured `value`. */
value_string?: string;
rank?: "preferred" | "normal" | "deprecated";
label?: string;
description?: string;
qualifiers?: Record<string, WikidataProperty> | null;
};Notes on the claim values:
- Statements Wikidata marks deprecated are dropped, and preferred ones
are sorted first, so
values[0]is the value Wikidata recommends. - Dates render at their stated precision and keep the sign of BCE years:
-0044-03-15. - Coordinates render as
"47.0105,28.8638". - Labels fall back to Wikidata's
mul("multiple languages") code, which is where many items now keep a name that is spelled the same everywhere.
enum SimpleEntityType {
EVENT = "E",
ORG = "O",
PERSON = "H",
PLACE = "P",
PRODUCT = "R",
WORK = "W"
}
type SimpleEntity = {
/** Always set. */
lang: string;
/** Always set. */
wikiDataId: string;
name?: string;
description?: string;
about?: string;
wikiPageId?: number;
wikiPageTitle?: string;
type?: SimpleEntityType;
types?: string[];
countryCodes?: string[];
data?: Record<string, string[]>;
categories?: string[];
redirectsToId?: string;
redirectsFromId?: string;
};The entity type is resolved from the DBpedia ontology types first, then from
the P31 claims against the generated Wikidata class tables, and finally from
the opening words of the extract.
data/countries.json and data/entity-types.json are derived from Wikidata
and checked in. Regenerate them against the live query service with:
npm run data:countries
npm run data:entity-typesdata:entity-types verifies a set of known classifications before writing, so
a bad expansion fails loudly instead of silently degrading type detection.
npm install
npm test # unit tests, fully mocked
npm run test:integration # hits the live Wikimedia and DBpedia APIs
npm run check # format, lint, typecheck, test, buildISC