API documentation
One resource in, one structured signal out.
NicheObserver accepts a domain, hostname, origin or HTTP(S) URL and returns a monthly CrUX snapshot with an explicit resource scope, adjusted Domain reach, direct Best origin reach, history since October 2022 and estimated country shares.
01 · Quickstart
Look up a resource
The canonical route is GET /v1/domain?resource=…. Authentication uses Authorization: Bearer. The resource is normalized by the Rust data plane with its embedded Public Suffix List; Laravel checks the request shape and quota but does not apply a second parser.
curl --get 'https://api.nicheobserver.com/v1/domain' \
--data-urlencode 'resource=https://www.example.co.uk/articles?id=42#intro' \
-H 'Authorization: Bearer ro_live_<public_id>_<secret>' A valid resource absent from the current snapshot is a business response with found: false. It arrives as HTTP 404 carrying the full body, not an error object, so a client that treats every 404 as a failure will discard the most common answer when scoring cold lists. It is not the same as malformed input, which returns 400 with an error key, nor an upstream failure. It consumes one lookup unit.
02 · Resource model
Domain, hostname, origin or URL
You can send the web resource you already have. NicheObserver resolves the registrable domain and reports what it actually used:
| Input | Scope | What is looked up |
|---|---|---|
example.com | domain | The registered domain and its observed origins. |
www.example.co.uk | domain | The registrable domain example.co.uk. |
https://app.example.com | origin | The exact scheme + host + port origin, with its parent domain context. |
https://example.com/path?q=1 | origin | The origin; path, query and fragment do not change CrUX identity. |
URLs with credentials, IP addresses, unsupported schemes and public-suffix-only values are rejected. IDNs are converted to the normalized representation returned in lookup. A domain lookup can expose best_origin and up to ten origins; an origin lookup filters the returned origins to the requested origin and can still report that the parent domain exists.
03 · Batch
Up to 1,000 resources per request
Use POST /v1/domains:lookup with the public property resources. Every array entry costs one lookup-rate token and, on capped plans, one daily lookup, including duplicates and strings that Rust later classifies as invalid. The whole batch is rejected when its weighted rate or remaining capped quota is insufficient; there is no partial admission.
curl -X POST 'https://api.nicheobserver.com/v1/domains:lookup' \
-H 'Authorization: Bearer ro_live_<public_id>_<secret>' \
-H 'Content-Type: application/json' \
-d '{"resources":["example.com","https://app.example.com/login","www.example.co.uk"]}' The response is 200 for a processed batch and keeps item-level statuses such as found, not_found, invalid and duplicate. The same lookup fields are available per item, including snapshot_month, reach_score, adjusted_reach_score, reach_score_model, popularity_rank_bucket, history, best_market and best_origin.
04 · Origins
Paginate the origin list deliberately
The main lookup returns the best origin and at most ten origins. For the full bounded list, call GET /v1/domain/{resource}/origins. Pages default to 1,000 entries and are capped at 5,000. Each page costs one unit.
curl --get 'https://api.nicheobserver.com/v1/domain/example.com/origins' \
--data-urlencode 'limit=1000' \
--data-urlencode 'cursor=0' \
-H 'Authorization: Bearer ro_live_<public_id>_<secret>' Read next_cursor until it is null. The cursor is an offset within one immutable snapshot, not a permanent identifier. When snapshot_month changes, discard it and restart at zero. An origin input returns only the matching origin; a domain input returns the domain's observed origin page.
05 · Authentication
Create, store and rotate keys
Sign in for free with Google or a verified email address, then create a key on the developers page in the form ro_live_<public_id>_<secret>. The secret has at least 256 bits of random entropy, is displayed once and cannot be recovered. Store it in a server-side secret manager.
- Give each integration its own key name; keys share the account limits.
- Create the replacement key before revoking the old key.
- Deploy the replacement and verify a harmless
/v1/statsrequest. - Revoke the old key. A revoked key cannot be reactivated.
Only the bearer header is accepted. Query strings, cookies, browser bundles and client-side extensions must never contain a secret. /v1/stats also requires a key and costs zero lookup units.
06 · Limits
Quotas, headers and stable errors
Limits are account-scoped across all keys. A batch of N resources consumes N lookup-rate tokens and, on capped plans, N daily lookups. Free has no daily cap and allows 5 lookups per second. On capped plans, the daily counter resets at 00:00:00 UTC; lookups never roll over.
| Plan | Lookups/day | Lookups/s | Batch | Keys |
|---|---|---|---|---|
| Free | Unlimited | 5 | 1,000 | 1 |
| Builder | 100,000 | 25 | 1,000 | 2 |
| Scale | 1,000,000 | 50 | 1,000 | 5 |
| Unlimited | Unlimited | 100 | 1,000 | 1,000 |
Authenticated lookup responses include the RateLimit-* lookup-token headers, X-Quota-Policy and X-Request-Id. Capped plans also receive X-Quota-Limit, X-Quota-Remaining and X-Quota-Reset; Free and Unlimited omit those three numeric quota headers. Program against the machine-readable error, not the English message.
| Status | Code | Meaning | Units |
|---|---|---|---|
| 400 | invalid_json | Malformed JSON or request shape. | 0 |
| 401 | invalid_api_key | Missing, unknown or revoked key. | 0 |
| 413 | batch_too_large | More than 1,000 entries or body over 512 KiB. | 0 |
| 429 | rate_limited / daily_quota_exceeded | Retry after the header-supplied delay. | 0 |
| 503/504 | dependency_unavailable / upstream_timeout | Technical dependency failure; observed upstream failures are refunded. | 0 net |
A business lookup with found:false costs one unit. It shares the 404 status with a route that does not exist, and is told apart by its body: a business answer carries lookup, domain and found, never an error key. A malformed request stopped before admission costs nothing.
07 · Client examples
curl, PHP, JavaScript and Python
These examples run on a server. Put NICHEOBSERVER_API_KEY in the process environment or a secret manager, never in a committed file.
PHP
$ch = curl_init('https://api.nicheobserver.com/v1/domain?resource=' . rawurlencode('example.com'));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NICHEOBSERVER_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true, 512, JSON_THROW_ON_ERROR);
curl_close($ch); JavaScript (Node.js)
const resource = encodeURIComponent('https://app.example.com/login');
const response = await fetch(`https://api.nicheobserver.com/v1/domain?resource=${resource}`, {
headers: { Authorization: `Bearer ${process.env.NICHEOBSERVER_API_KEY}` },
});
if (!response.ok) throw new Error((await response.json()).error);
const lookup = await response.json(); Python
import os
import requests
response = requests.get(
"https://api.nicheobserver.com/v1/domain",
params={"resource": "example.com"},
headers={"Authorization": f"Bearer {os.environ['NICHEOBSERVER_API_KEY']}"},
timeout=10,
)
response.raise_for_status()
lookup = response.json() 08 · Method
Buckets, markets and monthly freshness
CrUX buckets are ranges
adjusted_reach_score is the primary Domain reach signal, from 0 to 100. reach_score is the direct Best origin anchor, mapped from the source bucket; popularity_rank_bucket keeps that discrete range beside it. The adjusted score aggregates the observed footprint and can exceed the direct anchor, but remains below 100 unless the direct score is 100. Neither field is an exact position or a visit count. A score of 0 means the resource was not observed in that month.
Best market is a classification
best_market is a separate, conservative CrUX-derived classification. It can be resolved for the registered domain and independently for an origin. The public hint contains only country, basis and confidence. It does not claim a country-level allocation of activity; an absent result means not observed or not resolved, not a conclusion about the resource.
Freshness
snapshot_month is the YYYYMM release represented by the immutable lookup snapshot. The current artifact covers the latest month and the historical window extends back to October 2022. An observed:false history point means no record for that month. It is not an error and it is not a claim that the resource was inactive.
NicheObserver publishes blue/green-compatible artifacts with matching months. Clients should display the observation month alongside any stored result and restart origins pagination when the snapshot month changes.
09 · Glossary / Glossaire
Use these terms consistently
- CrUX / Chrome UX Report
- Google's public dataset of real-world Chrome user experiences. It is not a universal census of the web.
- Domain / domaine enregistré
- The registrable domain derived with the Public Suffix List, such as
example.co.uk. - Hostname
- A DNS host such as
www.example.com; the API may map it to its parent registrable domain. - Origin / origin
- Scheme, host and port together, for example
https://app.example.com. - Bucket / bucket
- A discrete source range or label. A bucket is not a one-to-one position.
- Best market / marché principal
- A cautious country classification with an explicit basis and confidence, not a country activity allocation.
- Snapshot month / mois du snapshot
- The YYYYMM data release represented by the loaded immutable artifact.
- Found, not_found, no_data
- Processing states. A successful response with no useful observation is distinct from an invalid input or technical outage.
10 · Sources
Public source, attribution and boundaries
The underlying source is Google's Chrome UX Report. The official BigQuery guide documents monthly tables, origin-level data and country datasets. Google's methodology explains eligibility, aggregation, filtering and fuzzing; the tools overview explains the different update cadences. We link to BigQuery directly for users who prefer the raw public dataset.
NicheObserver is an independent interface and API. It is not affiliated with, sponsored by or endorsed by Google. “Chrome”, “Google” and “Chrome UX Report” remain their respective owners' marks. We publish no per-domain SEO pages and do not present an interrogated resource as an indexable public profile.
Legal status: pre-launch draft. Terms/AUP and privacy summarize the intended behavior and remain subject to entity, payment, support and retention decisions.
Start with a lookup Read the CrUX article Country pages method