Files

172 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Native API
description: POST /scrape — the native TRAWL endpoint with full tier control.
---
# `POST /scrape` — Native API
The native endpoint exposes TRAWL's full feature set: tier capping, session IDs, and rich timing metadata.
## Request
```typescript
interface ScrapeRequest {
url: string
maxTimeout?: number // ms, default 60000
skipHttp?: boolean // skip Tier 1 (plain fetch), default false
maxTier?: 1 | 2 | 3 | 4 // cap escalation at this tier
sessionId?: string // sticky session override key
headers?: Record<string, string> // custom headers forwarded to the target
proxy?: string // per-request proxy override for Tier 3/4
}
```
### Fields
| Field | Type | Default | Description |
| ------------ | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url` | string | — | The URL to scrape |
| `maxTimeout` | number | 60000 | Max total time in milliseconds |
| `skipHttp` | boolean | false | Skip Tier 1 (go straight to browser) |
| `maxTier` | 14 | 4 | Never escalate beyond this tier |
| `sessionId` | string | hostname | Override the Redis session key |
| `headers` | object | — | Custom headers forwarded to the target across all tiers — see [Custom Headers](/api-reference/custom-headers) |
| `proxy` | string | — | Proxy URL used for this request's Tier 3/4 attempts instead of the configured `PROXY_URL`/`RESIDENTIAL_PROXY_URL` pool — see [Configuration § Proxies](/getting-started/configuration#proxies) |
## Response
```typescript
interface ScrapeResult {
url: string // final URL after redirects
html: string
cookies: Cookie[]
userAgent: string
statusCode: number
tier: 1 | 2 | 3 | 4 // which tier succeeded
sessionCached: boolean // true if a cached session was used
timings: TierResult[] // per-tier attempt history
totalMs: number
captchasSolved?: string[] // captcha types solved on the page itself (e.g. ['turnstile'])
proxyUsed?: boolean // true if the winning tier routed through a proxy (Tier 3 datacenter pool or Tier 4 residential pool/override)
}
interface TierResult {
tier: 1 | 2 | 3 | 4
status: 'success' | 'blocked' | 'needs-js' | 'timeout' | 'error' | 'skipped'
durationMs: number
reason?: string
}
```
## Examples
### Minimal request
```bash
curl -s -X POST http://localhost:8191/scrape \
-H "Content-Type: application/json" \
-d '{ "url": "https://nowsecure.nl" }' | jq '{tier, totalMs, sessionCached}'
```
### Force browser only (skip plain HTTP)
```bash
curl -s -X POST http://localhost:8191/scrape \
-H "Content-Type: application/json" \
-d '{
"url": "https://nowsecure.nl",
"skipHttp": true,
"maxTier": 3
}'
```
### Inspect timing breakdown
```javascript
const res = await fetch('http://localhost:8191/scrape', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://nowsecure.nl' }),
})
const result = await res.json()
console.log(`Tier used: ${result.tier}`)
console.log(`Session cached: ${result.sessionCached}`)
console.log(`Total: ${result.totalMs}ms`)
for (const t of result.timings) {
console.log(` Tier ${t.tier}: ${t.status} in ${t.durationMs}ms`)
}
```
### Example response
```json
{
"url": "https://nowsecure.nl",
"html": "<!DOCTYPE html>...",
"cookies": [
{ "name": "cf_clearance", "value": "abc123...", "domain": ".nowsecure.nl", "path": "/", "expires": 1700003600, "httpOnly": false, "secure": true }
],
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"statusCode": 200,
"tier": 2,
"sessionCached": true,
"timings": [
{ "tier": 1, "status": "needs-js", "durationMs": 85 },
{ "tier": 2, "status": "success", "durationMs": 512 }
],
"totalMs": 600
}
```
## Error response
HTTP status codes:
| Code | Meaning |
| ---- | -------------------------------------------------------------------- |
| 200 | `tier` succeeded |
| 400 | Malformed request body |
| 429 | Pool exhausted — all browsers busy past `BROWSER_ACQUIRE_TIMEOUT_MS` |
| 503 | Browser pool initializing |
| 500 | Internal error |
For 429 pool-exhaustion errors, the body is a **FlareSolverr v2 envelope** (same shape `/v1` uses) so clients can parse both endpoints uniformly:
```json
{
"status": "error",
"message": "Browser pool saturated, retry shortly",
"startTimestamp": 1700000000000,
"endTimestamp": 1700000015000,
"version": "2.0.0",
"solution": {
"url": "https://nowsecure.nl",
"status": 0,
"headers": {},
"response": "",
"cookies": [],
"userAgent": ""
}
}
```
For 400 / 503 the body is the native shape `{ "error": "Human-readable message" }`.
For 500 errors raised after at least one tier was attempted, the body also includes the
per-tier attempt history, so a failed request is still fully diagnosable from the response
alone — no need to check server logs:
```json
{
"error": "All tiers exhausted. Last failure: http-403",
"timings": [
{ "tier": 1, "status": "needs-js", "durationMs": 50, "reason": "cloudflare-challenge" },
{ "tier": 3, "status": "blocked", "durationMs": 2942, "reason": "http-403" },
{ "tier": 4, "status": "blocked", "durationMs": 7890, "reason": "http-403" }
]
}
```