Docs
API 1.39
Status
Concepts

The http tier

The cheapest way to read a page: what Kaabist can do without a browser, what makes a job need one, and how conditions behave on a document.

The http tier reads a page with one request and no browser: no JavaScript runs and nothing is laid out, and Kaabist extracts from the document that came back. It is the default for any program that only navigates and extracts, and it costs one compute credit per request where a browser costs five.

#When to use it

Most pages are documents: they arrive complete and say what they say in their markup, embedded JSON or ld+json. Any goto + extract program, including every url + extract job, starts here. You do not need to ask for it; you need to avoid steps that force a browser when a document would do, and to know what changes about conditions at this tier.

#What it fetches with

Not a plain HTTP client. A request from this tier carries a real browser's TLS and HTTP/2 fingerprint and a real browser's headers in a real browser's order, and goes out through the same proxy pool a browser job would use. A site that serves documents to browsers and blocks scrapers usually cannot tell the difference, and when it can, the job moves up a tier by itself.

Cookies persist across navigations inside one job, so a program that follows a redirect, collects a consent cookie and asks for the page again behaves like one browsing session. A bound session seeds those cookies. options.headers adds request headers to every request this tier makes.

#What it can read

Everything in the document: CSS, XPath, text and role locators, regex over text or HTML, and json locators over the JSON the page embeds (<script id="__NEXT_DATA__">, window.__INITIAL_STATE__, application/ld+json). A network locator works here too: the endpoints a program's network locators name are fetched alongside the document, so a program that reads a site's JSON API directly can run without a browser.

#What needs a browser

The http tier has a document, not a page. There is nothing to click, nothing has been laid out and no script has run, so a program containing any of these steps starts at the browser tier instead:

click · fill · press · hover · select · check · uncheck · upload · scroll · wait_for · evaluate · screenshot · download · paginate · await_input · set_session · capture_response · loop_until

A target inside an iframe also needs a browser: the http tier fetched one document and no frame in it. If a job reaches such a step at this tier, it moves up and records why:

{ "meta": { "tier": "browser", "escalations": [{ "from": "http", "to": "browser", "reason": "tier_insufficient:frame" }] } }

A page that looks like a document but is an empty shell, a <div id="root"> and a script, moves up for a different reason: the expected content is missing, and the page is classified empty_shell. See Tiers and escalation.

#Conditions at this tier

exists, absent, count, text, url, title, var and landmark behave exactly as they do at the browser tier. Two do not:

  • visible means exists here, and hidden means absent. Nothing was painted, and "cannot tell" is not "no": a price behind a tab is still the price.
  • network is always false. One request was made, by Kaabist, and nothing ran to make another. A program that waits for an API call belongs at the browser tier.

options.block_urls and options.assets are ignored, because this tier loads no subresources.

#The shared cache

A plain goto + extract job with no session and no inputs can be served from the shared cache when you set cache.max_age:

{ "url": "https://shop.example.com/p/1", "extract": { "title": "h1" }, "cache": { "max_age": 300 } }

A hit pays its compute credit and no proxy traffic, and says so with meta.cache: "hit" and a cache_hit warning. The eligibility rules are on Tiers and escalation.

#Worked example

Run a shop's product page, server-rendered with an ld+json block and __NEXT_DATA__:

{
  "url": "https://shop.example.com/p/1",
  "extract": {
    "title": "h1",
    "price": { "selector": ".price", "type": "money", "locale": "tr", "currency": "TRY" },
    "stock": { "json": "$.props.pageProps.product.stock", "type": "integer" }
  }
}

The request. One GET to /p/1 with a browser's fingerprint, through a datacenter proxy. meta.tier is http, meta.escalations is empty, and meta.steps lists the goto and the extract.

The snapshot. GET /v1/jobs/{id}/snapshot redirects to the stored snapshot: the URL and final URL, the status and headers, tier: "http", timings, and a reference to the stored HTML. Its network log is empty, because nothing else was fetched. stock came from the __NEXT_DATA__ JSON inside that HTML, without a browser.

The cost. meta.credits.breakdown shows compute: 1 and the proxy traffic of one document. The same job forced to the browser tier with options.prefer_tier: "browser" returns the same data and costs compute: 5, plus the traffic of the scripts and stylesheets a browser loads (images, fonts and trackers are blocked).

#Pitfalls

  • A precautionary wait_for. It forces the browser tier for the whole job. Use an expect on the goto instead, which works at this tier.
  • Reading prices that JavaScript fills in. A server-rendered skeleton (-, Loading) is classified placeholder_content and the job moves to the browser once; give such a field null_markers so a genuinely missing value is read as empty.
  • Waiting for a network response. A network condition never holds here. Read the endpoint with a network locator, or let the job run at the browser tier.
  • Expecting visible to filter hidden elements. It cannot at this tier; select the element you want with a more specific locator.

#Reference

Was this page helpful?