PloidDocs
Technographics (beta)

Technographics (beta)

Detect the technologies a website and its DNS show, with evidence and an assessment for each finding, from one domain.

Beta

Technographics is in beta for Scale and Custom workspaces. tech_id is the upstream catalogue slug for now and may change during the beta, when the Ploid technology catalogue lands. During the beta, name and category also come from the upstream catalogue and can change with it, and the evidence source_scope values may change. Other fields may be added; existing fields keep their meaning.

POST /v1/technographics

Send one domain and get back the technologies Ploid found on its website and in its DNS: frameworks, analytics, hosting, email providers, verification tokens and more. Every finding carries an assessment of how strong its evidence is. Direct findings cite the page, header or DNS record they came from; inferred findings name the technology that implies them.

Scans are static: Ploid reads the homepage and a few same-site pages over HTTP, plus the domain's public DNS records. A scan usually takes about 10 seconds and stops at 25. Pages are not rendered in a browser yet, so technologies that only appear after JavaScript runs can be missed. Ploid honors robots.txt, never logs in, and does not submit forms.

Requires an API key with the people:search scope. Older full-access keys that hold people:enrich and agent:chat also work. You can also try it in the API playground.

curl https://api.ploid.com/v1/technographics \
  -H "Authorization: Bearer $PLOID_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "domain": "acme.com",
    "freshness": { "max_age_days": 30 }
  }'

Request

FieldMeaning
domainThe website's domain, such as acme.com or www.acme.com. Paths, IP addresses and internal hosts are rejected with 422 invalid_domain.
freshness.max_age_daysOptional integer, 0 to 365 (default 30). The oldest stored scan to reuse. 0 asks for a fresh scan; see Freshness and caching below.

Response

{
    "data": {
        "domain": "acme.com",
        "canonical_domain": null,
        "status": "assessed",
        "source": "scan",
        "scanned_at": "2026-10-20T15:04:05.000Z",
        "technologies": [
            {
                "tech_id": "next-js",
                "name": "Next.js",
                "category": "javascript-frameworks",
                "categories": ["javascript-frameworks", "web-frameworks"],
                "scope": "website",
                "assessment": "observed",
                "version": "14.2.3",
                "channels": ["static"],
                "first_observed_at": "2026-10-20T15:04:06.000Z",
                "last_observed_at": "2026-10-20T15:04:07.000Z",
                "inferred_from": [],
                "evidence": [
                    {
                        "source_url": "https://acme.com/",
                        "channel": "static",
                        "source_scope": "website_delivery",
                        "signal": "headers:x-powered-by",
                        "match": "Next.js 14.2.3",
                        "rule_id": "9c1f...",
                        "artifact_sha256": "4b2e...",
                        "observed_at": "2026-10-20T15:04:06.000Z",
                        "version": "14.2.3"
                    }
                ]
            },
            {
                "tech_id": "react",
                "name": "React",
                "category": "javascript-frameworks",
                "categories": ["javascript-frameworks"],
                "scope": "website",
                "assessment": "inferred",
                "version": null,
                "channels": [],
                "first_observed_at": null,
                "last_observed_at": null,
                "inferred_from": ["next-js"],
                "evidence": []
            },
            {
                "tech_id": "google-workspace",
                "name": "Google Workspace",
                "category": "email",
                "categories": ["email"],
                "scope": "email_routing",
                "assessment": "observed",
                "version": null,
                "channels": ["dns"],
                "first_observed_at": "2026-10-20T15:04:05.000Z",
                "last_observed_at": "2026-10-20T15:04:05.000Z",
                "inferred_from": [],
                "evidence": [
                    {
                        "source_url": "https://acme.com/",
                        "channel": "dns",
                        "source_scope": "email_routing",
                        "signal": "dns:MX",
                        "match": "aspmx.l.google.com",
                        "rule_id": "51ad...",
                        "artifact_sha256": "e07c...",
                        "observed_at": "2026-10-20T15:04:05.000Z",
                        "version": null
                    }
                ]
            }
        ],
        "coverage": { "pages": 3, "dns": true, "limits": [] },
        "versions": { "collector": 5, "rules": "...", "assessment": "2026-09-28.1", "catalog": "upstream-..." }
    },
    "meta": {
        "request_id": "req_...",
        "credits_charged": 1,
        "remaining_credits": 3999,
        "freshness": { "max_age_days": 30 }
    }
}
FieldMeaning
domainThe normalized domain you asked for.
canonical_domainWhere the homepage redirected, when that differs from domain; otherwise null.
statusassessed, partial, blocked, or failed; see below.
sourcescan for a scan run for this request, cache for a stored scan (see Freshness and caching).
scanned_atWhen the scan behind this result started.
technologiesOne record per technology and scope, at most 300.
coveragepages captured, whether dns answered, and limits: plain-language notes on anything that cut or capped the scan.
versionsThe collector, rule, assessment and catalogue revisions that produced the result, for comparing results over time.

Each technology record has a name, its first upstream category and all categories, a scope and an assessment, a version when every sighting in that scope agrees, the channels it was seen on (static or dns; browser is reserved for a future rendered scan), and when it was first and last seen. A record keeps up to five evidence items, and very large results can carry fewer; inferred records have none. Each item names the source_url (query strings, fragments and credentials removed), the channel and observed_at of the sighting, the signal that matched (such as scriptSrc, headers:server or dns:MX), a match excerpt of up to 256 characters, a version when the sighting carried one, and the rule_id and artifact_sha256 of the rule and input that matched. source_scope is the scanner's finer-grained scope (such as website_delivery or dns_alias); its values are beta and may change.

Status

statusMeaning
assessedCollection finished within its budgets.
partialSomething was captured, but the deadline or a budget cut coverage, or only DNS answered.
blockedNo page was captured: robots.txt disallowed it or answered 429 or 5xx, the page answered 401 or 403, or the domain opted out of crawling by Ploid.
failedNothing usable came back: no pages and no DNS records.

An empty technologies list is not proof that a site uses nothing; read coverage.limits and status before drawing conclusions. A result with no page captured can still list website technologies seen in the headers or cookies of an error or refusal response, such as the CDN in front of a homepage that answered 502 or 403.

Scopes and assessments

A technology can appear once per scope, assessed only on that scope's evidence. A vendor in both an SPF record and a website script is two records: configured under email_authorization and observed under website.

scopeWhere it was seen
websitePages, response headers, scripts, stylesheets and other resources the site serves.
email_routingMX records: who receives the domain's email.
email_authorizationSPF records: who may send email for the domain.
domain_verificationVerification tokens published in the domain's DNS TXT records.
dns_hostingNS and alias records: who hosts the domain's DNS or fronts its hostnames.
certificateThe issuer of the site's TLS certificate.

website records are not all use: a Content-Security-Policy entry is configured, a verification meta tag on a page is verification_only, and a product named in page text is a content_candidate. Filter on assessment, not scope, when you want the technologies a site uses.

assessmentMeaning
observedSeen in the site's own code, headers or DNS. The strongest signal.
configuredReferenced or authorized, such as an SPF include or a Content-Security-Policy entry. Not proof the product is in use.
verification_onlyOnly a verification token. The domain once proved ownership to the service; that says little about current use.
content_candidateNamed in page content, such as a blog post or logo wall. Review before claiming the company uses it.
inferredImplied by an observed technology (Next.js implies React). inferred_from lists the parents; there is no evidence.

A match means a public signal matched a fingerprint. It is not a purchase record and does not prove company-wide adoption.

Freshness and caching

Ploid keeps each scan and serves the newest assessed or partial scan of the domain that is no older than freshness.max_age_days (default 30). A blocked result is reused for up to 24 hours and a failed one for up to 10 minutes. Otherwise Ploid scans the site and returns source: "scan". Stored results come back with source: "cache". meta.freshness echoes the window applied.

max_age_days: 0 asks for a fresh scan, with one exception: a domain scanned in the last 10 minutes is served from that scan. This minimum rescan interval protects the sites being scanned, so repeated requests inside it return the same result, with source: "cache".

Once a website opts out of crawling by Ploid, its stored scans are no longer served, whatever they found (empty, blocked and failed results too) and however recent, even from the last 10 minutes. That holds when the domain, the site its homepage redirected to, or a page or host a stored scan's evidence cites opts out, whenever that was, and when any other host or page of the website opts out after the scan started. When the domain itself opted out, its next request runs as a live scan that returns status: "blocked", source: "scan", no technologies and the coverage note "domain opted out", free and without contacting the site; later requests get that answer from the cache under the blocked rule above. When only a page or host opted out, the next request runs a normal live scan that leaves it out, and for a few seconds after the opt-out each request for that website scans it again. If Ploid cannot check its opt-out list within 3 seconds before serving a stored scan, the request fails with 503 technographics_unavailable, retryable and free, without scanning.

Live scans are limited per workspace to 2 at a time and 200 started in any rolling hour; /v1/openapi.json publishes the limits in force. Over either, the request fails with 429 scan_capacity_exceeded, a Retry-After header and error.retry_after_seconds; cached results are not limited this way. A live scan that fails on Ploid's side with a retryable 503, and the blocked answer for a domain that opted out, do not count toward the hourly quota.

Pricing

A billable result costs 1 credit per domain, whether it came from a fresh scan or the cache. A result is billable only when at least one page of the website was captured (coverage.pages above 0) and it has at least one record that is not inferred with scope website (a technology seen on the site itself). Results with no page captured are free, whatever records they carry: DNS-only results (email_routing, email_authorization, domain_verification, dns_hosting, certificate), and results whose website records come only from an error or refusal response. blocked, failed and empty results are free too. meta.credits_charged shows what was charged. Enterprise contracts can set a different per-domain price.

Every request needs one domain's price available before it runs, whether or not its result turns out to be billable and whether or not it comes from the cache: in the workspace balance, else 402 insufficient_acu, and within the API key's daily and monthly budgets, else 402 daily_budget_exceeded or monthly_budget_exceeded. The hold on the key's budget is released when the result is free.

Plans

Technographics is included on the Scale and Custom plans. Workspaces on other plans, such as Growth, API Pro, pay as you go and the free trial, receive 403 plan_upgrade_required.

Errors

No error is charged. The one exception is 503 billing_unavailable: Ploid had the result but could not confirm whether its charge went through.

ConditionStatus and code
Missing or invalid credential401 missing_authentication, invalid_api_key, expired_api_key, revoked_api_key
The workspace cannot currently use the API402 active_account_required
Not enough credits, or the key's daily or monthly budget hit402 insufficient_acu, daily_budget_exceeded, monthly_budget_exceeded
The key lacks people:search403 insufficient_scope
The workspace plan does not include Technographics403 plan_upgrade_required
The Idempotency-Key was used for a different request, or its first request is still running409 idempotency_conflict, idempotency_in_progress
Invalid request body422 validation_failed
Not a public website domain422 invalid_domain
Request rate limit429 rate_limited
The workspace reached its live-scan limit (2 at a time or 200 an hour)429 scan_capacity_exceeded
Scanners are busy or unavailable503 technographics_busy, 503 technographics_unavailable
The scan failed in a way a retry would repeat503 technographics_scan_failed
The charge could not be confirmed503 billing_unavailable

429 responses carry Retry-After, and 503 technographics_busy and technographics_unavailable carry retryable: true; retry them with bounded backoff. 503 billing_unavailable carries retryable: false: do not retry it under a new Idempotency-Key, which could charge twice; contact support with its request_id. Retrying with the same key replays that answer. 503 technographics_scan_failed also carries retryable: false: the scan failed on Ploid's side in a way that would repeat for this domain, so contact support with its request_id instead of retrying; it counts toward the hourly live-scan quota. 403 plan_upgrade_required and 429 scan_capacity_exceeded do not use up the Idempotency-Key, so the same key works after an upgrade or a wait. See Errors & rate limits.