Perceive
POST /v2/perceive renderizza un URL una sola volta in un browser reale e
ti restituisce ogni output che richiedi da quel singolo render: Markdown,
HTML ripulito o grezzo, uno screenshot, un PDF, l'inventario di link e
immagini e dati strutturati (metadati della pagina, JSON-LD, intestazioni,
tabelle). Sostituisce una serie di chiamate separate — url-to-markdown,
url-to-screenshot, url-to-pdf, oltre al tuo scraping personalizzato — con
una sola richiesta.
Ecco la chiamata utile più piccola. Invia un URL e ricevi Markdown pulito e i metadati strutturati della pagina:
curl -X POST https://api.enconvert.com/v2/perceive \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"outputs": ["markdown", "structured"]
}'
La risposta contiene un URL di download pre-firmato per il file Markdown e il blocco strutturato inline:
{
"operation_id": "per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
"status": "completed",
"url": "https://example.com/pricing",
"url_final": "https://example.com/pricing",
"content_hash": "9f2b8c1a...d4e5",
"render_quality": 0.93,
"cache_hit": false,
"outputs": {
"markdown": {
"url": "https://spaces.example.com/...signed...",
"object_key": "env/files/4127/v2-perceive/per_3f9a..._markdown.md",
"size_bytes": 8421,
"content_type": "text/markdown; charset=utf-8",
"expires_in": 900
}
},
"structured": {
"metadata": {
"title": "Pricing",
"description": "Simple, usage-based pricing."
},
"structured_data": [
{"@type": "Product", "name": "Pro", "offers": {"price": "99"}}
]
},
"extraction_tier": "heuristic",
"tokens": {"input": 0, "output": 0},
"cost_cents": 0.0,
"duration_ms": 6230,
"warnings": []
}
Da segnalare subito.
/v2/perceiveè un endpoint V2 con un proprio contatore di quota. I piani di conversione V1 non includono alcuna operazione di perceive V2 — ti serve un piano che includa V2 per chiamarlo. Vedi la pagina dei prezzi per le quote per ciascun tier.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/v2/perceive |
Percepisce un singolo URL e restituisce gli output che hai richiesto. |
GET |
/v2/perceive/{operation_id} |
Recupera di nuovo un'operazione passata con URL di download firmati ex novo. |
POST |
/v2/perceive/batch |
Percepisce fino a 1.000 URL che condividono lo stesso set di opzioni. |
GET |
/v2/perceive/batch/{job_id} |
Interroga lo stato e i risultati per ciascun URL di un batch. |
Content-Type: application/json su ogni POST.
Authentication
Autentica con una chiave privata nell'header X-API-Key per le chiamate
server-to-server. Questo è il percorso usato dagli esempi qui sotto.
X-API-Key: sk_live_your_private_key
Funzionano anche le chiavi pubbliche con un token bearer JWT, usando lo
stesso flusso di ogni altro endpoint — genera un token con la tua chiave
pk_, poi invialo come Authorization: Bearer <token>. Il flusso
completo, incluso il domain locking e il refresh del token, è nella
guida all'autenticazione.
Ogni chiave API porta con sé un allowlist di endpoint consentiti. Se
/v2/perceive non è nella lista della chiave, la richiesta viene
rifiutata con 403.
How perceive works
Una richiesta innesca un render del browser tramite un singleton Chrome headless condiviso, poi materializza ogni output da quel render. Non paghi mai due volte per la stessa pagina in una singola chiamata.
- Render. La pagina viene caricata in Chrome headless. I banner dei cookie vengono chiusi, la pagina viene scrollata per innescare i contenuti caricati in modalità lazy, gli header sticky vengono gestiti e alle immagini viene dato il tempo di caricarsi — la stessa pipeline di cattura che alimenta l'endpoint url-to-pdf.
- Materialise. Dal DOM renderizzato, perceive costruisce tutto ciò
che hai elencato in
outputs: Markdown, HTML ripulito/grezzo, link, immagini, uno screenshot, un PDF. - Extract. Se hai richiesto l'output
structured, perceive esegue un passaggio euristico per i metadati della pagina, JSON-LD, intestazioni e tabelle. Se invii anche unoschemae il tuo piano include il tier LLM, un modello Anthropic Claude Haiku riempie lo schema quando il passaggio euristico risulta insufficiente. - Score. Un punteggio di qualità del render (0.0–1.0) segnala le pagine che sembrano bloccate da protezioni anti-bot o nascoste dietro un login wall, così puoi distinguere un render reale da una pagina di challenge.
Gli output binari e di testo (Markdown, HTML, screenshot, PDF, il JSON di
link e immagini) vengono caricati nello storage e restituiti come URL
pre-firmati che scadono dopo 15 minuti. Il blocco structured viene
restituito inline nel JSON. Recupera di nuovo qualsiasi operazione con
GET /v2/perceive/{operation_id} per ottenere un nuovo set di URL firmati.
Request parameters
Core
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
string |
— | La pagina da percepire. Deve iniziare con http:// o https://. Massimo 2.048 caratteri. Obbligatorio. |
outputs |
string[] |
["markdown", "structured"] |
Quali output produrre. Vedi Outputs. |
extract |
string[] |
[] |
Quali campi strutturati estrarre quando structured è in outputs. Vedi Structured extraction. |
schema |
object |
null |
Uno schema JSON che descrive i campi che vuoi estrarre. Attiva il tier di estrazione LLM nei piani che lo includono. |
cache_mode |
string |
"enabled" |
enabled, bypass, o refresh. Vedi Caching. |
Outputs
outputs accetta qualsiasi combinazione di questi nomi:
| Output | Returned as | What you get |
|---|---|---|
markdown |
signed URL | Markdown pulito dal contenuto principale, con link e immagini risolti in URL assoluti. |
markdown_fit |
signed URL | Markdown "Fit" — una variante ridotta e più densa, ottimizzata per le finestre di contesto degli LLM. |
html_cleaned |
signed URL | L'HTML renderizzato con script, stili e boilerplate rimossi. |
html_raw |
signed URL | L'HTML renderizzato completo, esattamente come prodotto dal browser. |
screenshot |
signed URL | Un PNG del viewport alla dimensione del viewport richiesta (o di default). |
screenshot_full_page |
signed URL | Un PNG dell'intera pagina che cattura tutta l'altezza dello scroll. |
pdf |
signed URL | Un PDF della pagina. Accetta l'intera superficie di pdf_options (vedi sotto). |
links |
signed URL | Un array JSON di ogni link trovato, con URL assoluti e testo dell'anchor. |
images |
signed URL | Un array JSON di ogni immagine, con src assoluto e testo alt. |
structured |
inline JSON | Dati strutturati estratti dalla pagina (il campo di risposta structured). |
Rendering and waiting
| Parameter | Type | Default | Description |
|---|---|---|---|
viewport |
object |
1920 x 1080 |
{"width": <int>, "height": <int>}. Larghezza 320–3840, altezza 240–2160. |
mobile |
boolean |
false |
Renderizza con un viewport mobile (390 x 844) a meno che viewport non sia impostato esplicitamente. |
wait_for |
string |
null |
Attende dopo la navigazione un selettore CSS (".price" o "css:.price") o un'espressione JS ("js:window.dataReady === true"). |
wait_timeout_ms |
integer |
30000 |
Per quanto tempo wait_for può attendere, in millisecondi. 0–60.000. Un timeout degrada a un warning; la pagina viene catturata così com'è. |
js_code |
string |
null |
JavaScript da eseguire sulla pagina dopo la navigazione. Massimo 20.000 caratteri. Un errore diventa un warning, non un fallimento. |
block_resources |
string[] |
[] |
Tipi di risorse da interrompere prima che vengano caricate. Uno qualsiasi tra image, media, font, stylesheet, script, xhr, fetch, websocket, manifest, other. Utile per render più veloci e di solo testo. |
respect_robots |
boolean |
false |
Quando è true, un URL non consentito dal robots.txt del sito viene rifiutato con 403. |
pdf_options |
object |
null |
Formato pagina, margini, intestazioni, piè di pagina, scala e orientamento per l'output pdf. Lo stesso oggetto di url-to-pdf. Senza pdf_options, perceive produce un'unica pagina continua, identica byte per byte a url-to-pdf V1. |
Authenticated and custom requests
| Parameter | Type | Default | Description |
|---|---|---|---|
auth |
object |
null |
HTTP Basic Auth per la pagina di destinazione: {"username": "...", "password": "..."}. |
cookies |
array |
null |
Cookie da iniettare prima della navigazione. Massimo 50. Ognuno necessita di name, value, e o domain o url. |
headers |
object |
null |
Header di richiesta personalizzati. Massimo 20. Nomi bloccati: host, content-length, transfer-encoding, connection, upgrade, te, trailer. |
proxy_url (Business+),
geolocation, e action_chain sono accettati dallo
schema della richiesta ma oggi restituiscono 422. Arriveranno in una
release successiva; inviarli ora ti dice esattamente quale manopola non è pronta
invece di ignorarla silenziosamente.
Structured extraction
Quando structured è in outputs, la lista extract controlla quali
campi perceive estrae. Non chiedere nulla e il default sarà metadata e
structured_data.
extract value |
Field in structured |
Status |
|---|---|---|
metadata |
metadata |
Attivo |
structured_data |
structured_data (JSON-LD) |
Attivo |
headings |
headings |
Attivo |
tables |
tables |
Attivo |
main_content |
main_content (testo, limitato a 50.000 caratteri) |
Attivo |
all |
si espande in ogni campo attivo qui sopra | Attivo |
prices |
— | Non ancora — restituisce un warning, omesso |
contacts |
— | Non ancora — restituisce un warning, omesso |
technologies |
— | Non ancora — restituisce un warning, omesso |
Per essere chiari: prices, contacts, e technologies sono nomi
riservati. Richiederne uno oggi non genera errore — finisce nell'array
warnings e viene scartato da structured.
Schema-driven extraction
Invia uno schema per estrarre campi specifici in structured.extracted:
{
"url": "https://example.com/product/widget",
"outputs": ["markdown", "structured"],
"schema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"in_stock": {"type": "boolean"}
}
}
}
Il tier di estrazione LLM (Anthropic Claude Haiku) riempie lo schema, e si
attiva solo quando valgono tutte queste condizioni: hai inviato uno
schema, il tuo piano include il tier LLM (Starter e superiori), la
pagina non è stata segnata come bloccata, e il passaggio euristico ha
lasciato vuoti i campi dello schema. Quando viene eseguito,
extraction_tier è "llm", e tokens e cost_cents riportano quanto è
costata quell'estrazione; altrimenti extraction_tier è "heuristic" ed
entrambi sono zero.
Nota. L'estrazione da schema ha un tetto rigido per proteggere il tuo conto: una singola estrazione ha un limite per richiesta, e la spesa giornaliera per progetto ha un limite per piano. Se viene raggiunto un limite, perceive restituisce il risultato euristico con una nota in
warningsinvece di spendere troppo. Su un piano senza il tier LLM, ottieni solo datistructuredeuristici.
Response
Sia POST /v2/perceive che GET /v2/perceive/{operation_id}
restituiscono lo stesso oggetto.
| Field | Type | Description |
|---|---|---|
operation_id |
string |
ID opaco (per_...). Usalo con l'endpoint GET e citalo al supporto. |
status |
string |
queued, processing, completed, o failed. |
url |
string |
L'URL che hai inviato. |
url_final |
string |
L'URL dopo i redirect. |
content_hash |
string |
SHA-256 della pagina renderizzata. Pilota la cache di 1 ora. |
render_quality |
number |
0.0–1.0. I punteggi bassi segnalano challenge anti-bot o login wall. |
cache_hit |
boolean |
true quando il risultato proviene dalla cache invece che da un render nuovo. |
outputs |
object |
Mappa del nome dell'output verso {url, object_key, size_bytes, content_type, expires_in}. Gli URL firmati scadono in 900 secondi. |
structured |
object |
Dati strutturati inline, presenti quando structured è stato richiesto. |
extraction_tier |
string |
heuristic, css, o llm. |
tokens |
object |
{input, output} token LLM usati. Zero a meno che il tier LLM non sia stato eseguito. |
cost_cents |
number |
Costo LLM in centesimi per questa operazione. Zero a meno che il tier LLM non sia stato eseguito. |
duration_ms |
integer |
Tempo di render end-to-end. |
error |
string |
Impostato solo quando status è failed. |
warnings |
string[] |
Note non fatali: un timeout di wait_for, un extract saltato, un flag di pagina bloccata. |
Retrieve an operation
Gli URL firmati scadono dopo 15 minuti. Per scaricare un output più tardi, recupera di nuovo l'operazione — perceive ri-firma ogni URL dalle object key memorizzate. Non avviene alcun nuovo render, quindi questo non consuma quota.
curl https://api.enconvert.com/v2/perceive/per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7 \
-H "X-API-Key: sk_live_your_private_key"
Un ID di operazione sconosciuto, o uno che appartiene a un altro progetto,
restituisce 404 — l'esistenza non viene mai rivelata tra progetti.
Batch perception
POST /v2/perceive/batch percepisce una lista di URL che condividono uno
stesso blocco options. Ogni URL viene renderizzato attraverso la stessa
pipeline di una chiamata singola e produce la propria riga di operazione.
curl -X POST https://api.enconvert.com/v2/perceive/batch \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://example.com/a",
"https://example.com/b",
"https://example.com/c"
],
"options": {"outputs": ["markdown"]},
"output_mode": "manifest"
}'
I batch di 10 URL o meno vengono eseguiti inline e rispondono 200 con
ogni risultato popolato. I batch più grandi rispondono 202 con un
job_id; gli URL vengono drenati uno alla volta e tu interroghi per i
risultati:
curl https://api.enconvert.com/v2/perceive/batch/{job_id} \
-H "X-API-Key: sk_live_your_private_key"
La risposta del batch riporta l'avanzamento aggregato e contiene un risultato perceive completo per ciascun URL una volta renderizzato:
{
"job_id": "bat_8c1a...",
"status": "partial",
"output_mode": "manifest",
"total": 3,
"completed": 2,
"failed": 1,
"pending": 0,
"items": [
{"operation_id": "per_...", "status": "completed", "url": "https://example.com/a"},
{"operation_id": "per_...", "status": "completed", "url": "https://example.com/b"},
{"operation_id": "per_...", "status": "failed", "url": "https://example.com/c"}
]
}
status è queued, processing, completed, failed, o partial
(alcuni URL sono riusciti, altri sono falliti). Imposta output_mode su
zip per raggruppare ogni artefatto in un unico ZIP, restituito sotto il
campo zip una volta che il batch è terminato. L'accesso ai batch e la
dimensione massima del batch sono limitati dal piano; vedi la pagina dei
prezzi.
Caching
cache_mode controlla come perceive tratta la sua cache di risultati di 1
ora, indicizzata per il tuo progetto, l'URL, e le opzioni di richiesta che
influenzano il render.
cache_mode |
Behaviour |
|---|---|
enabled (default) |
Restituisce un risultato dalla cache quando una richiesta identica è stata renderizzata nell'ultima ora. cache_hit è true, cost_cents è 0. |
bypass |
Salta la cache e renderizza ex novo. |
refresh |
Renderizza ex novo e sostituisce la voce in cache. |
Da segnalare: un cache hit conta comunque come una operazione di perceive sulla tua quota mensile. La quota misura le operazioni, non i render del browser — la cache ti fa risparmiare tempo di render, non quota.
Code examples
curl — Markdown only
curl -X POST https://api.enconvert.com/v2/perceive \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/blog/post",
"outputs": ["markdown"]
}'
curl — Markdown plus structured data
curl -X POST https://api.enconvert.com/v2/perceive \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"outputs": ["markdown", "structured"],
"extract": ["metadata", "structured_data", "tables"]
}'
curl — Full outputs plus PDF
curl -X POST https://api.enconvert.com/v2/perceive \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/report",
"outputs": ["markdown", "html_cleaned", "screenshot_full_page", "pdf"],
"pdf_options": {"format": "A4", "print_background": true}
}'
Python
import requests
response = requests.post(
"https://api.enconvert.com/v2/perceive",
headers={"X-API-Key": "sk_live_your_private_key"},
json={
"url": "https://example.com/pricing",
"outputs": ["markdown", "structured"],
"extract": ["metadata", "tables"],
},
)
response.raise_for_status()
data = response.json()
# Download the Markdown artifact from its signed URL
markdown_url = data["outputs"]["markdown"]["url"]
markdown_text = requests.get(markdown_url).text
print(data["structured"])
print(markdown_text)
Node.js
const res = await fetch("https://api.enconvert.com/v2/perceive", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_live_your_private_key"
},
body: JSON.stringify({
url: "https://example.com/pricing",
outputs: ["markdown", "structured"],
extract: ["metadata", "tables"]
})
});
const data = await res.json();
// Download the Markdown artifact from its signed URL
const markdownText = await fetch(data.outputs.markdown.url).then(r => r.text());
console.log(data.structured);
console.log(markdownText);
Se chiami EnConvert da Claude, Cursor, o un altro client MCP, la stessa
capacità è esposta come tool perceive_url — vedi la pagina del server
MCP.
Plan gating
Le operazioni di perceive V2 sono un contatore separato dalle conversioni V1. I piani V1 non includono alcuna quota di perceive; ti serve un piano che includa V2.
| Plan | Perceive operations / month | Schema extraction (LLM tier) |
|---|---|---|
| Free | 50 | Non incluso |
| Starter | 850 | Claude Haiku |
| Pro | 8,500 | Claude Haiku |
| Business | 42,500 | Claude Haiku |
| Enterprise | Unlimited | Incluso |
L'accesso ai batch e i limiti di dimensione per batch, il supporto a
basic-auth/cookie/header, e proxy_url (Business+, quando verrà
rilasciato) sono limitati dal piano. I numeri attuali si trovano su la
pagina dei prezzi.
Error responses
| Status | Condition |
|---|---|
400 Bad Request |
L'URL non è http(s), contiene credenziali incorporate, o risolve a un indirizzo privato, loopback, o link-local (protezione SSRF). |
400 Bad Request |
auth non valido (manca username/password), cookies (non è un array, oltre 50 voci, campi mancanti), o headers (non è un oggetto, oltre 20 voci, nome bloccato). |
401 Unauthorized |
Chiave API / token JWT mancante o non valido. |
402 Payment Required |
Perceive non è nel tuo piano attuale, o la tua quota mensile di perceive è esaurita. |
403 Forbidden |
/v2/perceive non è negli endpoint consentiti della chiave API. |
403 Forbidden |
Batch non disponibile nel tuo piano, o la dimensione del batch supera il limite del tuo piano. |
403 Forbidden |
respect_robots=true e il robots.txt del sito non consente l'URL. |
404 Not Found |
operation_id o job_id sconosciuto, o uno appartenente a un altro progetto. |
422 Unprocessable Entity |
La validazione della richiesta è fallita (enum errato in outputs/extract, wait_timeout_ms fuori range, viewport fuori dai limiti). |
422 Unprocessable Entity |
proxy_url, geolocation, o action_chain è stato inviato — riservato a una release successiva. |
500 Internal Server Error |
Il render è fallito. Il messaggio include l'operation_id da citare al supporto. |
Il riferimento completo dei codici di stato è nella guida ai codici di errore.
Limits
| Limit | Value |
|---|---|
| Lunghezza URL | 2.048 caratteri |
wait_timeout_ms |
0–60.000 ms |
Lunghezza js_code |
20.000 caratteri |
| Larghezza viewport | 320–3.840 px |
| Altezza viewport | 240–2.160 px |
| Cookie per richiesta | 50 |
| Header personalizzati per richiesta | 20 |
Extract main_content |
50.000 caratteri |
| URL per batch per richiesta | 1.000 (limite schema; il limite di batch del tuo piano è inferiore) |
| Soglia batch inline | 10 URL (i batch più grandi vengono eseguiti in modo asincrono) |
| TTL cache risultati | 1 ora |
| Scadenza URL firmato | 15 minuti |
| Operazioni di perceive mensili | Dipendente dal piano (Free: 50) |