peeringdb — PeeringDB public API
| id / implementation | peeringdb (apps/worker/src/connectors/datasets/peeringdb.ts) |
| kind / mode / priority | dataset / api / 2 |
| API | https://www.peeringdb.com/api/ (fac, campus, org, ix, ixfac, netfac, net, carrier, carrierfac), always ?depth=0 |
| entities | NormalizedFacility (peeringdb:fac:<id>), NormalizedIxp (peeringdb:ix:<id>), NormalizedCampus (peeringdb:campus:<id>), NormalizedOperator (peeringdb:org:<id> facility owners; peeringdb:net:<id> NSP networks and peeringdb:carrier:<id> carrier objects, kind carrier) |
| schedule | facilities: daily, ixps: daily (incremental since=), campuses/operators/carriers: weekly; full refresh every params.fullRefreshDays (7) |
| requests per run | 5 primary + 9 lookup/join tables, each URL once per run (memoized), ≥ 2 s apart → ~14 requests, ≈ 25 MB |
| attribution | "Data: PeeringDB" |
License / terms (verified 2026-09-11) — READ THIS
PeeringDB publishes no open-data license (no CC/ODbL). https://docs.peeringdb.com/ links only to the Acceptable Use Policy, https://www.peeringdb.com/aup, which states (verbatim):
"Except for Internet operational purposes approved by PeeringDB, no part of the PeeringDB data may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, recording, or otherwise, without prior permission of PeeringDB on behalf of the copyright holders. Any use of this material to target advertising or similar activities is explicitly forbidden and will be prosecuted. […] The PeeringDB data may not be passed on in bulk to any other person or organization unless approved by PeeringDB. Any request to pass on information to any other person or organization will be evaluated on the statement of purpose outlined by the requestor. Users will not be able to download the full contents of the database unless the intended use is for "Internet operational issues". These words are tightly defined and would include network trouble-shooting, abuse reporting, and Internet research and analysis. It would not include compiling marketing lists, demographic mapping, or any other commercial application."
"© 2004-2026 PeeringDB All Rights Reserved. By using this service, you agree to adhere to our AUP."
Reading: DataCenterIndex's use (a structured index of facilities/IXPs for research and analysis, attributed) fits "Internet research and analysis", but the AUP requires PeeringDB's approval for bulk reproduction and forbids "commercial application". Action for the owner before publishing PeeringDB-derived records: e-mail support@peeringdb.com with a statement of purpose and request approval (and an API key, see below). Until then the connector is functional but should be considered "verification/reconciliation input", and the UI must show "Data: PeeringDB" wherever a PeeringDB-sourced fact is displayed. The YAML license field carries the AUP quote so sources.license is accurate.
Query limits (https://docs.peeringdb.com/howto/work_within_peeringdbs_query_limits/, retrieved 2026-09-11)
"Duplicate queries: Repeated anonymous identical requests with a response size above 100kb are being limited to 1/hour. Repeated anonymous identical requests of any size are being limited to 2/minute. Query rate limit: Anonymous queries limited to 20/minute per IP address. Authenticated queries limited to 40/minute per user or organization […] Please use API Keys when automating queries to PeeringDB and set a User-Agent header that identifies the unique software you are using […] We also encourage you to leave at least two seconds between queries."
Consequences implemented:
- every upstream URL is fetched once per run (
fetchJsonOnce, memo keyed by runId) and requests are spaced byparams.minDelayMs(2 000 ms),fetch.rpm: 20,concurrency: 1; PEERINGDB_API_KEY(env) → headerAuthorization: Api-Key …for the authenticated tier (recommended; also lets PeeringDB contact us);- HTTP 429 is logged with
Retry-After; a facility document whose join tables are unavailable is aborted (no partial carrier/IX lists) and retried at the next run; - during verification an identical anonymous
fac?depth=0request repeated within the hour was throttled ("Expected available in 36 minutes"). Never run two full loads within an hour without an API key.
robots.txt only disallows /register, /account/login, /username-retrieve, /reset-password → /api/ is allowed (respectRobots: true).
Documents and mapping
facilities (fac?depth=0[&since=]) — composed with campus, ixfac(fields), ix(fields), netfac(fields), net?info_type=NSP(fields), carrier, carrierfac(fields):
| field | source |
|---|---|
name, aliases |
name; aka, name_long (distinct, non-empty) |
operatorName / operatorKey |
org_name / peeringdb:org:<org_id> |
campusName / campusKey |
campus.name / peeringdb:campus:<campus_id> |
address, city, regionName, countryIso2, postalCode |
address1, address2; city; state; country (ISO-2); zipcode |
geo |
latitude/longitude → precision exact, source dataset:peeringdb; null when absent (never geocoded here) |
status |
ok → operational; pending/deleted records are skipped (deletions are not propagated as closures — a PeeringDB deletion is often a merge/duplicate) |
facilityType |
carrier_hotel when ix_count ≥ 3 and net_count ≥ 150 (params.carrierHotelMinIx/MinNets), else colocation |
carriers |
names of PeeringDB carrier objects present (carrierfac) ∪ networks present (netfac) whose info_type/info_types contains NSP |
ixps |
IX names present (ixfac) |
website, description |
website (http(s) only), notes |
externalIds |
peeringdb_fac, peeringdb_org, peeringdb_campus, clli |
facts |
networkCount (net_count), ixCount (ix_count), carrierCount (carrier_count), property (Owner/Lessee), diverseServingSubstations, availableVoltageServices — per-field provenance dataset-field:<name> |
Not used: created (registration date, not an opening date), region_continent, npanxx, contact fields (personal data).
ixps (ix?depth=0) — name, nameLong, city, countryIso2, regionContinent, website, networkCount = net_count, facilityKeys from ixfac (peeringdb:fac:<fac_id>), externalIds { peeringdb_ix, peeringdb_org }.
campuses (campus?depth=0) — name, operatorName = org_name, city, countryIso2, externalIds { peeringdb_campus, peeringdb_org } (PeeringDB campuses carry no coordinates → geo: null).
operators (org?depth=0&fields=…) — only organisations owning ≥ 1 ok facility (join on fac?fields=id,org_id,status): name, aliases, website, hqCountryIso2, hqCity, kind: null (not guessed), externalIds { peeringdb_org }.
carriers (net?depth=0&info_type=NSP&fields=… + carrier) — kind: "carrier", externalIds { peeringdb_net, asn, peeringdb_org } for NSP networks; { peeringdb_carrier, peeringdb_org } for carrier objects.
Incremental mode: state peeringdb:lastRunAt / peeringdb:lastFullAt; after a full load, subsequent runs add since=<lastRunAt − 1 h> (unix seconds) to the five primary URLs (PeeringDB returns objects updated since, including status: deleted). Join/lookup tables are always fetched in full (presence lists are recomputed from scratch). State is written in discover() (not in dry runs); a run that dies midway loses at most one incremental window, recovered by the weekly full load.
Verified live (2026-09-11)
node node_modules/tsx/dist/cli.mjs scripts/try-connector.ts config/connectors/peeringdb.yaml --limit 5 --json /tmp/peeringdb.json (anonymous, no API key)
fac?depth=0 200 1.1 s → 5 860 records → 5 860 facilities, 5 860 valid, 0 rejected
ix?depth=0 429 retry-after 1255 s (identical anonymous request > 100 kB repeated within the hour: the probe 38 min earlier) → 0 entities
campus?depth=0 200 → 76 campuses, 76 valid
org?depth=0&fields=… 200 1.3 s → 2 605 facility-owning organisations, 2 605 valid
net?depth=0&info_type=NSP&fields=… 200 0.6 s → 4 193 NSP networks + 286 carrier objects = 4 479 carrier operators, all valid
TOTAL 13 020 entities, 13 020 valid, 0 rejected, 0 warnings, 11 fetches, 26 s (2 s pacing)Facilities coverage: 5 255 / 5 860 with coordinates (exact), 5 860 with a country, 3 720 with ≥ 1 carrier/NSP present, 2 158 with ≥ 1 IX present, 206 attached to a campus; 57 typed carrier_hotel (ix_count ≥ 3 and net_count ≥ 150), 5 803 colocation.
Sample: peeringdb:fac:1 "Equinix DC1-DC15,DC21-DC22 - Ashburn" — operator Equinix, Inc. (peeringdb:org:2), campus "Equinix Ashburn" (peeringdb:campus:14), 21715 Filigree Ct, Building F, Ashburn VA 20147-6205 US, geo 39.016363/−77.459023 exact, carrier_hotel, carriers list (123NET, AT&T US, Angola Cables…), facts networkCount 516 / ixCount 8 / carrierCount 14.
IX document, re-verified once the hourly window reopened (03:48 EDT, --url https://www.peeringdb.com/api/ix?depth=0, group inferred from the path):
ix?depth=0 200 0.3 s → 1 323 records → 1 323 IXPs, 1 323 valid, 0 rejected (2 fetches: ix + ixfac)Coverage: 1 323 with a country, 1 318 with a website, 1 226 with networkCount, 960 with ≥ 1 facilityKeys (from 4 521 ixfac rows).
Sample: peeringdb:ix:1 "Equinix Ashburn" (nameLong "Equinix Internet Exchange Ashburn", US, North America, 347 networks, facilityKeys peeringdb:fac:1, peeringdb:fac:710, peeringdb:fac:15438, externalIds peeringdb_ix 1 / peeringdb_org 2).
Quirks / gaps
- Anonymous tier: the
fac?depth=0dump (~6 MB) can be fetched once per hour per IP. Use an API key in production. netfull dump is 40 MB → we only fetch NSP networks with afields=projection (~0.9 MB);netfacwithfields=is ~3.9 MB (vs 14 MB).- Presence lists can be long (Equinix Ashburn: 516 networks, of which the NSP subset is kept) —
carriersis a set of names, counts live infacts. - PeeringDB
orgrecords for facility owners are 3 000+ organisations, many small ISPs registering their own site as a "facility"; treatnet_count = 0facilities as low-signal in ranking. - Deleted/merged facilities are not propagated (needs a "missing from full load" reconciliation pass in ingest to flag
closed/merged — out of scope for the connector).