SitesGraph

A European initiative to structure the web

Docs

What you can do with SitesGraph, the API, the npm package, and how we handle data.

Why use SitesGraph

Find companies by what they are and where they are

"All hotels in Barcelona", "restaurants within 10 km of Antwerp", "Shopify shops in the Netherlands", "dentists in Ghent with an online booking tool". Every crawled website gets a category (Hospitality › Accommodation › Hotel), a location with coordinates, and a verdict (is it a real business?). Search them on Explore or with /v1/search, and export to CSV.

Turn a website into structured data

One call gives you a company's name, legal name, VAT number (checked), address, opening hours, emails, phone numbers, social profiles, languages and more, as JSON. Use it to fill a CRM, enrich sign-ups, build a directory, or give an AI agent clean facts instead of raw HTML.

Prepare social media posts from a website

Every record lists the site's images with their alt text, its logo, brand colours, page titles, descriptions and keywords per page. That's the raw material for posts and visuals about a company (a restaurant's dishes, a hotel's rooms, a shop's products) without asking the owner for files. Check the image rights before you publish.

Audit a website and help its owner

About 55 checks across SEO, accessibility (useful with the European Accessibility Act in force since 2025), marketing, trust and security, a score, and concrete tips in plain language. Share the report with the owner.

Market research

Which booking tools do restaurants in Belgium use? How many webshops accept Bancontact? Which CMS do Dutch municipalities run? Technologies, payment methods, delivery options and review widgets are detected on every crawled page.

Monitor and keep data fresh

Records are crawled again periodically: see which businesses closed (parked or unreachable), changed address, or launched a webshop.

API

All endpoints return JSON. No key is needed to read. Admin endpoints (the crawler and the dataset downloads) need Authorization: Bearer <ADMIN_TOKEN>; in a browser, the crawler page asks for it as a password.

EndpointWhat it returns
GET /v1/domains/{domain}The full record. Crawled live the first time (5–20 s), stored after. ?cached=false crawls again.
GET /v1/domains?limit=10The most recently indexed domains (summaries).
GET /v1/searchSearch the index. Filters below. ?format=csv for a spreadsheet.
GET /v1/categoriesThe category tree, with how many domains are in each.
GET /v1/page-typesThe page types, and suggestions for new ones from the data.
GET /v1/technologiesSearch the 7,600+ technologies: q, category, seen=1.
GET /v1/statsTotals, queue, crawler, index and disk.
GET /v1/crawlerThe crawler's status (admin).
GET /v1/export/summaries.csv · .parquetThe whole dataset, one row per domain (admin). See the dataset.
POST /v1/crawler/start · /stopStart or stop the crawler (admin).
POST /v1/crawler/seedsAdd domains to the queue: one per line, or { "domains": [] } (admin).

Search filters

ParameterExample
categoryhotelA category id; parents include their children (hospitality finds hotels and restaurants). See the tree.
placeAntwerpenAny level: a city, province, region, country (any language: België) or continent (Europe).
cityBarcelonaCity, province, region or any of a company's locations.
country, continentBE · EuropeISO country code; continent name.
tldbe,nlDomain extension(s).
near, kmAntwerpen · 10Within a radius of a city or lat,lng.
technologyShopifyUses this technology.
page_typebookingHas this kind of page.
modelwebshopBusiness model: webshop, bookings, saas, lead_generation, gift_cards, donations, content, brochure.
has_email, has_phone1Only with contact details.
min_score60Minimum website score.
language, freshnessnl · activeMain language; active, stale or abandoned.
statusbusinessDefault business; all, parked, for_sale, …
qbakeryText in the domain, name, title or description, or one of the site's keywords.
sort, limit, offsetdistance · 50 · 0score (default), name, distance, newest.
facet_limit50How many values per facet. Facets count the matches per category, continent, country, region, province, city, TLD, language and technology.
curl "http://localhost:3000/v1/search?category=hotel&city=Barcelona"
curl "http://localhost:3000/v1/search?category=restaurant&near=Antwerpen&km=10&format=csv"

npm package: look up one domain

The crawler and all the analysis are a standalone package. No database or server needed.

npm install sitesgraph

const { lookup } = require("sitesgraph");
const record = await lookup("restaurantbink.be");
console.log(record.site_status.verdict);   // "business"
console.log(record.category.category.path); // Hospitality › Food & drink › Restaurant
console.log(record.location.city);         // "Turnhout"

npx sitesgraph restaurantbink.be --summary

The technology rules (Wappalyzer, GPL-3.0) are downloaded once on first use, into ~/.cache/sitesgraph.

Self-hosting

Run SitesGraph on your own server (AWS or any Linux machine) with install.sh or Docker. Crawl a country, export the data (gzip NDJSON or Parquet) and merge exports from several servers: the newest record wins. See docs/deploy.md in the repository.

The dataset

The SitesGraph dataset is managed by Autonomous BV, as the base of a Global Trends system: following companies over time to learn what works and what doesn't. Which sectors grow, which technologies and business models companies adopt or drop, which companies stay active and which disappear.

We share it for research and with partners who want to contribute (crawling capacity, data, corrections, expertise). Get in touch with Autonomous BV.

Download and query it

On your own server, download every summary (one row per domain: name, status, category path, city, province, region, country, continent, coordinates, contact details, score, technologies, keywords…). These downloads are admin-only:

curl -H "Authorization: Bearer $ADMIN_TOKEN" -o sitesgraph.csv     https://your-server/v1/export/summaries.csv
curl -H "Authorization: Bearer $ADMIN_TOKEN" -o sitesgraph.parquet https://your-server/v1/export/summaries.parquet

Or from the command line on the server (works while it runs): npm run cli -- csv (a .csv.gz), npm run cli -- parquet (summaries + full records), npm run cli -- export (full records as NDJSON). Then query it with DuckDB:

duckdb -c "SELECT province, count(*) AS bakeries
           FROM 'sitesgraph.csv'
           WHERE category_path LIKE '%Bakery%' AND country = 'BE'
           GROUP BY 1 ORDER BY 2 DESC"

In the CSV, lists (category path, technologies, keywords) are joined with "; ". The Parquet file keeps them as real lists.

Data limitations

SitesGraph reads public websites, without AI and without paid sources. That works for most business websites, but not for all of them, and not for every field. Know these limits before you rely on the data. The full list of edge cases is in docs/limitations.md.

Measured on ~100 European sitesFound
Sites we could read84%
Category (of real businesses)93%
City76%
Email · phone66% · 79%
VAT number29%

"Found" means we have a value, not that it's right. A set of verified sites is checked on every change.

Sites we can't read

Where we guess

Coverage

Data & GDPR