Amazon Nova Act can reason about a web page and act on it. In 2026, the hard part of a production web agent isn’t the model. It’s web access: reaching the live web reliably, with the right geo-targeting, and while staying compliant. This article pairs Nova Act with Bright Data’s web-access layer for AI agents, and the measurements here come from live runs.
TL;DR
The bottleneck for a production AI web agent is web access, not the model. The fix is a split: Amazon Nova Act makes the multi-step browser decisions, and Bright Data’s web-access layer handles access, compliance, and scale. Bright Data’s Data for AI 2026 report finds 97% of AI organizations depend on real-time web data, and 90% say access restrictions are limiting their AI initiatives.
The complete runnable script, with every import, schema, and helper, is in the companion repo. Clone that if you want to run it, not copy-paste from here.
To follow along you need Python 3.10+, pip install nova-act, and a Nova Act API key from nova.amazon.com/act. You also need a Bright Data account with a Browser API zone, plus an API key for the data-layer calls. Node.js is needed only for the Web MCP section.
Why the browser-agent default falls short
The obvious approach with a browser agent is to let it do everything. Open a page, dismiss the cookie banner, scroll, extract. It looks good in a demo, but for most data work it’s the wrong default.
- It’s heavy. A single real consumer page (an eBay search) transferred about 3.4 MB through the browser. Multiply that by millions of pages and you pay to move the whole rendered web, including every image, to extract three fields.
- It’s fragile when it acts. Pointed at booking.com, Nova Act threw
ActActuationErrorwhile fighting popups and lazy-loaded content, even though the page loaded fine. Plain reads are usually reliable. The heavy multi-step actuation breaks down there. - It’s non-deterministic. Reliability drops fast. Ten 90%-reliable steps come out near
0.9¹⁰ ≈ 35%unless you plan for it.
None of this makes browser agents useless. So use them for what only they can do (the multi-step actions and decisions), and push everything else down to infrastructure.
What Amazon Nova Act is, and what it is not
Nova Act is an AWS SDK, version 3.4.x in mid-2026, moving from research preview toward production, for building browser agents in Python. Its design idea is the opposite of one giant prompt. You break a workflow into small, atomic, reliable commands and connect them with ordinary Python. The two commands are an action and a typed read:
from nova_act import NovaAct
from pydantic import BaseModel
class Product(BaseModel):
title: str | None = None
price: str | None = None
availability: str | None = None
with NovaAct(starting_page="https://example.com/product/123") as nova:
nova.act("search for wireless headphones") # an action
data = nova.act_get( # a typed read
"Return the product title, price, and availability.",
schema=Product.model_json_schema(),
)
With a Pydantic schema, act_get can turn a page into typed data with no brittle selectors. Nova Act drives a real Chromium through Playwright underneath, a detail that matters for the connection. Nova Act gives you reasoning, navigation, and structured extraction. It doesn’t give you any answer to the open web’s hostility. It has no geo reach, no unblocking at scale, no built-in compliance. That’s not its job. It’s the infrastructure layer’s job.
Bright Data, the web-access layer
The layer is built around one idea: unlocking the web for your AI. Web MCP, a Model Context Protocol server, gives an agent structured web tools it calls directly. Web Unlocker and the SERP API return clean pages and search results. The Web Scraper APIs and Datasets do bulk structured retrieval. The Browser API is a cloud Chrome you drive remotely, for the cases where an agent needs to act. Underneath is a network of 400M+ residential IPs across 195 countries, with common CAPTCHA challenges, fingerprint management, and geo-targeting handled.
In Bright Data’s Data for AI 2026 survey, 87% of organizations agree a “two-tier internet” is emerging, an agentic web of automated traffic running alongside the human one. And 65% already rely on a dedicated web data infrastructure provider rather than build access in-house.
This is a layer, not a tool. Your agent stack changes. The web-access layer beneath it doesn’t. So the engineering question is never browser versus API in the abstract. You split the job in two: the agent handles the decisions, the infrastructure handles the access.
The architecture, brain on top and infrastructure underneath
Nova Act sends actions down, and structured data comes back.

Nova Act makes the decisions and actions. Bright Data’s web-access layer handles access, compliance, geography, and scale, then reaches the live web.
For the action mode, Nova Act attaches to Bright Data’s Browser API over the Chrome DevTools Protocol (CDP), the same protocol that Playwright (and therefore Nova Act) already speaks. You swap the browser and keep the agent.
Wiring it up, and the setup errors to expect
Create a Browser API zone (its CAPTCHA solver is on by default) and the dashboard gives you a URL:
wss://brd-customer-<id>-zone-<name>:<password>@brd.superproxy.io:9222
That string comes from the zone’s Overview tab, under Access details.

The Browser API zone’s Access details. The dashboard hands you the wss:// string with inline credentials, the auth+@host form shown at the top of the panel. Modern Playwright rejects that inline form, so split_cdp() moves the credentials into an Authorization: Basic header. The IP Allowlist on the left is the other pitfall. If your IP isn’t listed there, the call returns an empty body and the reason arrives in the response headers rather than the status code.
The Invalid URL error: Playwright rejects inline wss:// credentials
Paste that straight into Nova Act and it fails:
playwright._impl._errors.Error: BrowserType.connect_over_cdp:
Invalid URL: wss://brd-customer-...:[email protected]:9222
This is a common first-run failure. Modern Playwright, version 1.56, bundled with Nova Act 3.4, rejects credentials embedded in a WebSocket URL. The dashboard shows the inline form because it works with older clients, not with the Playwright inside Nova Act. The fix is to strip the credentials out and pass them as an Authorization: Basic header through cdp_headers.
import os
import base64
def split_cdp(raw_url: str) -> tuple[str, dict | None]:
"""Bright Data gives an inline-credential wss URL; Playwright rejects that.
Move credentials into a Basic auth header. (Parsed manually because
Python 3.14's urlsplit also rejects the multi-colon netloc.)"""
scheme, sep, rest = raw_url.partition("://")
if not sep or "@" not in rest:
return raw_url, None
creds, _, hostport = rest.rpartition("@")
user, _, pwd = creds.partition(":")
token = base64.b64encode(f"{user}:{pwd}".encode()).decode()
return f"{scheme}://{hostport}", {"Authorization": f"Basic {token}"}
endpoint, headers = split_cdp(os.environ["BRIGHTDATA_CDP_URL"])
with NovaAct(starting_page=URL, cdp_endpoint_url=endpoint, cdp_headers=headers,
logs_directory="runs/demo") as nova: # NOTE: logs dir must already exist
...
The intermittent InvalidScreenResolution trap
The other big pitfall is the viewport. Bright Data’s remote browser gives Nova Act a window around 1280×585, which is smaller than the roughly 1600×900 Nova Act expects. Nova Act doesn’t degrade gracefully. It throws an intermittent hard InvalidScreenResolution ActError. It’s intermittent because each cloud session gets a slightly different size. That makes it hard to diagnose, and easy to misread as a flaky agent that needs a retry. Force a supported size on the connected page:
with NovaAct(starting_page=URL, cdp_endpoint_url=endpoint, cdp_headers=headers,
screen_width=1600, screen_height=900, logs_directory="runs/demo") as nova:
nova.page.set_viewport_size({"width": 1600, "height": 900}) # force a supported size to stop InvalidScreenResolution
...
Two smaller traps: StartFailed and a missing logs_directory
Don’t pass headless=True with cdp_endpoint_url, because the remote browser is already headless and you get StartFailed. And logs_directory must exist before you start, because Nova Act validates the path and won’t create it.
What the agent is for
With the connection wired, the question is what to make the agent do. A plain read is the least distinctive thing it offers, and Bright Data’s Web Scraper APIs do that better and cheaper. An agent is worth more than a scraper because it can act.
Its most useful action is to reach data behind a form. There is no static URL to know in advance and no API there, so a scraper has nothing to hit. An agent can fill the form and read the result. So we pointed Nova Act at Drugs@FDA, the authoritative U.S. drug-approval database, and asked it to retrieve a drug record:
nova.act("Search for the drug named ibuprofen") # fill the form, submit
drug = nova.act_get("Return the brand name, active ingredient, application number, "
"and marketing status of the first result.", schema=Drug.model_json_schema())
Its own trace shows a four-step flow that no URL captures. It typed into the search box and pressed Enter, found the first result collapsed and clicked to expand it, clicked through to the detail page, then read the fields:
{'drug_name': 'ACETAMINOPHEN AND IBUPROFEN', 'active_ingredient': 'ACETAMINOPHEN; IBUPROFEN',
'application_number': '214836', 'marketing_status': 'Over-the-counter'} # all 4 DOM-grounded
Those four steps, in the browser:

A real recording of the run, frame by frame. Nova Act searches “ibuprofen” on Drugs@FDA, opens the first result, and reads ANDA #214836, the same application number the run returned.
We ran it across different drugs to confirm consistency: aspirin gave 8-HOUR BAYER (#016030), and metformin gave ACTOPLUS MET (#021842). With ibuprofen, that’s 3/3, every field grounded. This is where the agent justifies its cost. The agent fills the form and navigates to authoritative, form-gated public data that a scraper can’t reach. Grounding AI in deep-web public data is a real problem. On a cooperative, well-structured site, it’s reliable.
The long tail
The same approach covers the long tail, the niche sites with no pre-built scraper. Bright Data’s Web Scraper APIs already cover over 100 of the high-value ones. Pointed at BoardGameGeek, Nova Act returned a clean six-field record, Catan / 1995 / 3,4 players / 60,120 min / rating 7.1 / lowest price. You verify it against the live DOM through nova.page, the Playwright handle, in the same session:
assert game.parsed_response["bgg_rating"] in nova.page.inner_text("body") # 7.1 -> present
Two grounding lessons emerged. Normalize before comparing, because the page’s en-dash 3,4 against the agent’s hyphen 3-4 is a false mismatch, not a hallucination. And verify in-session, never later, because a live marketplace price was grounded at extraction time and gone on reload, so a second-pass check of volatile data can be wrong. With those, all six fields grounded. It held under a five-way concurrent run too.
The boundary is about terrain, not the task. Nova Act struggles on hostile consumer sites like eBay and booking.com: bot-defended eCommerce with cookie walls, custom variation widgets, and lazy-loaded content. On those sites, the multi-step actions slow down and turn flaky, and heavy chains time out. It’s reliable on cooperative, structured sites: public databases, internal apps, and well-built forms. It’s brittle on hostile consumer ones. Keep actions few, verify every field with nova.page, retry, and let Bright Data’s data layer handle the hostile, high-volume cases.
What geo-routing actually changes
No local browser does this without the same routing infrastructure underneath. We ran the same hotel search on a major booking site, routed through three countries by adding -country-XX to the Bright Data username:
| Routed through | Currency | Sample nightly rates |
|---|---|---|
| United States | US$ | US$30, US$128, US$171 |
| United Kingdom | £ | £30, £167, £194 |
| Germany | € | €40, €194, €225 |
The currency switches cleanly and the prices reflect real market differences, not conversion. We read these three with a raw browser, because geography is the infrastructure’s job, not the agent’s. The agent extracts whatever market it’s pointed at, the same as the US-routed eBay run. This matters for competitive price monitoring, fare aggregation, or any case where you need to see it as a local customer does.
What matters for a run is which IP you exit from, so we checked each routed session. The exit IPs came back as real consumer ISPs, not datacenter ranges: a major US cable provider, a UK broadband carrier, a German mobile network, a Japanese carrier, and a Brazilian regional ISP.
That’s the difference between looking local and being local. The request arrives as a real residential user in that country. So the prices, inventory, and anti-bot treatment are much closer to what a local customer sees than to what a flagged datacenter range gets.
Compliance, the 90% problem
This is where access restrictions matter, the 90% problem itself: most AI organizations say those restrictions are limiting their AI initiatives. Here Bright Data acts as the guardrail. Pointed at a flight metasearch site, the agent was refused:
Page.navigate: Requested URL (kayak.com/flights/...) is restricted in accordance
with robots.txt. Ask your account manager to get full access (brob)
A raw local browser scraped the same site with no problem moments earlier. Bright Data refused. Refusing is the more capable behavior, not the weaker one. Bright Data enforces robots.txt and gates sensitive targets behind Know Your Customer (KYC) checks by default, the approach an enterprise legal team can approve.
For most enterprise targets you’re fine. In our checks, booking.com, Expedia, Hotels.com, Airbnb, eBay, Best Buy, and Tripadvisor all cleared. Restricted ones are an account-manager conversation, not a workaround. The infrastructure handles the access-side compliance so your code doesn’t have to.
The cost and reliability budget
A procurement reviewer asks two questions: how reliable is it, and what does it cost.
Reliability
Reliability has one main lever and one hard ceiling. The lever is the viewport fix. Before we set it, about half of all runs failed on InvalidScreenResolution, and that one bug was most of what looked like a flaky agent.
After the fix we measured it on a real site, not a sandbox. A five-way concurrent eBay read returned 5/5, every value confirmed in the live DOM through nova.page, in 47s against about 198s sequential, 4.2×. Each session ran on a fresh Bright Data IP, which avoids concentrating requests on a single IP.
That isn’t free linear scaling. We pushed it to 12 concurrent and 8 of 12 came back clean. That’s the concurrency ceiling on the free and pay-as-you-go tiers, not the agent breaking. Real enterprise volume means raising the zone’s concurrency limit and budgeting retries, not assuming five sessions scale to five thousand for nothing.

The gain from concurrency is real but not linear. Past the plan’s concurrency ceiling, 8 of 12 concurrent reads came back clean.
A single light action (sort, then read) needed the occasional retry, and the failures that remained were transient StartFaileds at session start. So break work into small idempotent steps, wrap them in retries, budget about 1.2 to 1.5×, and verify every output with nova.page.
The remaining limit is terrain. On the structured side it stays reliable. Three Drugs@FDA lookups each ran the same flow: fill, submit, click-expand, navigate, extract. All three came back 3/3, every field grounded, though slow at about 50 to 90 seconds each. On the consumer side, the multi-step chains still slow down and time out.
The reliability numbers in one view:
| Scenario | Result | What it means |
|---|---|---|
| Before the viewport fix | ~half of runs failed | InvalidScreenResolution, the dominant failure |
| 5-way concurrent read, post-fix (eBay) | 5/5 grounded | 47s vs ~198s sequential, 4.2×, fresh IP per session |
| Pushed to 12 concurrent (raw) | 8/12 | the pay-as-you-go concurrency ceiling, not the agent |
| Single light action (sort, then read) | occasional retry | the misses are retryable StartFaileds |
| Multi-step FDA form, 3 drugs | 3/3 grounded | cooperative site, but slow at ~50,90s each |
Cost
Bandwidth cost is measurable, and model cost is the open question. The Browser API bills per GB, about $8/GB pay-as-you-go (all prices here are as of mid-2026). We measured real page weight through it:
| Page type | Weight | Browser API @ $8/GB |
|---|---|---|
| Heavy consumer page (eBay search) | ~3.4 MB | ~$0.027/page → ~$27 / 1,000 pages |
| Light page (sandbox product) | ~0.2 MB | ~$0.0016/page → ~$1.60 / 1,000 pages |
Add the retry multiplier, then add Nova Act’s inference cost, which isn’t publicly priced today. The free tier meters how much you collect, and production runs through AWS without a published price. So the budget comes down to two lines. The Browser API bandwidth is a known, predictable line item. The agent’s inference is the cost you must confirm with AWS before scaling.
Moving 3.4 MB to extract three fields is also why, for bulk work, you don’t drive a browser at all. The data layer bills per request instead of per gigabyte. The SERP API and Web Unlocker run about $1.50 per 1,000, against ~$27 per 1,000 heavy pages through the browser.
When to use the agent, and when to use the data layer
Bright Data ships Web MCP and Web Scraper APIs so you don’t drive a browser for everything. The dividing line is decision complexity:
- Fixed, known-schema pull, like price and stock for 100,000 SKUs. Don’t use an agent. A Web Scraper API returns just the record, with no 3.4 MB page, no inference cost, and far fewer transient failures. It’s cheaper and more reliable.
- Reasoning the scrape can’t capture: multi-step navigation, conditional logic (for example, the cheapest refundable fare that meets your constraints), form submission, web-app QA, or an unfamiliar portal with no pre-built scraper. That’s where Nova Act and the Browser API earn their cost.
The rule: if you can express it as a fixed scrape or an API call, do that. In real systems the two compose. Nova Act drives the decision flow and passes bulk retrieval to Bright Data’s structured APIs.
The data layer in practice
“Use the data layer for bulk” is the usual advice. Here it is, run against the same Bright Data account, three calls, no browser, no agent.
Structured search in one call (SERP API), fresh parsed search results to ground an AI, returned as JSON:
requests.post("https://api.brightdata.com/request",
headers={"Authorization": f"Bearer {BRIGHTDATA_TOKEN}"},
json={"zone": "serp_api2", "format": "raw", # gl/hl pin the locale so results are stable
"url": "https://www.google.com/search?q=amazon+nova+act+sdk&brd_json=1&gl=us&hl=en"})
9 organic results → 1. github.com/aws/nova-act · 2. nova.amazon.com/act · 3. docs.aws.amazon.com/nova-act …
Any URL to clean LLM-ready markdown (Web Unlocker), the same FDA drug record our agent reached by filling a form, fetched directly:
json={"zone": "web_unlocker", "format": "raw", "data_format": "markdown",
"url": "https://www.accessdata.fda.gov/.../ApplNo=214836"}
→ 8.4 KB of clean markdown, one call, no browser, no CAPTCHA handling, no parsing.
A known source to just the structured record (Web Scraper API), trigger a pre-built collector and get clean fields, never the page. We ran the Crunchbase scraper for one company:
requests.post("https://api.brightdata.com/datasets/v3/trigger?dataset_id=gd_l1vijqt9jfj7olije",
headers={"Authorization": f"Bearer {BRIGHTDATA_TOKEN}"},
json=[{"url": "https://www.crunchbase.com/organization/anthropic"}]) # -> snapshot_id, then poll
→ 89 structured fields (employees, HQ, CB rank, status, funding …),
ready in ~70s, no browser, no agent, no 3.4 MB page, no parsing.
The contrast is the architecture. The agent was the right tool here because you had to act to reach the data. No URL existed, so it searched the form and navigated to application 214836. Once a URL exists, or you need search results or bulk known-schema records, you don’t drive a browser. You call the data layer. It’s more deterministic, faster, and cheaper, with far less of the agent’s reliability budget. Nova Act discovers and acts. Bright Data’s data layer retrieves at scale.
The agent calls Bright Data’s tools directly
The integrations so far are orchestrated by hand. We called SERP and Web Unlocker, then handed the agent a browser. There’s a tighter integration. You give Nova Act Bright Data’s Web MCP server as tools, and the agent itself decides when to search, scrape, or discover. Nova Act runs on AWS’s Strands framework, so it accepts MCP tools directly:
from strands.tools.mcp import MCPClient
from mcp import StdioServerParameters
from mcp.client.stdio import stdio_client
bd_mcp = MCPClient(lambda: stdio_client(StdioServerParameters(
command="npx", args=["-y", "@brightdata/mcp"], env={"API_TOKEN": BRIGHTDATA_TOKEN})))
with bd_mcp:
tools = bd_mcp.list_tools_sync() # search_engine, scrape_as_markdown, discover, batch…
with NovaAct(starting_page="https://example.com", tools=tools,
cdp_endpoint_url=endpoint, cdp_headers=headers) as nova:
nova.act_get("Use the search_engine tool to find 'Amazon Nova Act SDK'; "
"return the top result's URL.", schema=Out.model_json_schema())
We ran it, and the agent’s own trace shows it. “The tool call was successful and returned information of the search. The top organic result is ‘https://github.com/aws/nova-act’…” and it returned {'top_result_url': 'https://github.com/aws/nova-act'}. The agent chose Bright Data’s search_engine tool itself, Bright Data ran the search, and the agent used the result. It took one act call, about 32s, with no scraping of a search page that a browser agent would likely get blocked on anyway.
That’s the difference between using two tools together and one agent that calls the other itself. The agent gets five tools directly in this run: search_engine, scrape_as_markdown, search_engine_batch, scrape_batch, and discover. That’s a clean and compliant path for the jobs that a browser agent does worst: search and bulk fetch.
The combined pipeline, breadth and depth
Each component so far stands alone. Combined, they build a grounded, structured intelligence record on a topic. You pull breadth from the open web, and depth from a form-gated authoritative source. We ran it on GLP-1 drugs, a high-profile pharmaceutical category:
# 1. BREADTH , Bright Data SERP API discovers authoritative sources (no browser)
sources = serp_api("Ozempic semaglutide")[:3]
# 2. FETCH , Bright Data Web Unlocker pulls the top source as markdown (no browser)
context = web_unlocker(sources[0])
# 3. DEPTH , Nova Act fills the Drugs@FDA form for the authoritative record (agent)
fda = nova_act_fda("semaglutide") # verified against the live DOM
Real, end-to-end output:
{
"web_sources": ["ozempic.com", "mayoclinic.org/…semaglutide…", "accessdata.fda.gov/…/209637lbl.pdf"],
"web_context_chars": 59270,
"fda_authoritative": {"drug_name": "OZEMPIC", "active_ingredient": "SEMAGLUTIDE",
"application_number": "209637", "marketing_status": "Discontinued"},
"fda_grounded": true
}
Each half did something the other couldn’t. The data layer searched the open web in two API calls and returned three authoritative sources and 59 KB of clean LLM-ready context, with no browser and no agent. The agent went where the data layer couldn’t reach on its own. It filled the FDA search form and navigated to the authoritative regulatory record, application 209637, status Discontinued for that product row, data behind a form with no URL.
And the two confirm each other. The data layer independently returned the FDA label 209637lbl.pdf for the same application number that the agent reached by acting. Breadth confirms depth.
This run also shows a failure you plan for. The agent’s FDA step failed on the brand name “Ozempic”, with ActAgentFailed three times, and succeeded on the active ingredient “semaglutide”. That’s the reliability cost of the terrain. It’s why you verify with fda_grounded: true and budget retries.
The same pipeline, a different industry
This works beyond pharmaceuticals, and we verified it. We ran the identical pipeline on a different industry, financial compliance. SERP found the firm’s web presence, its own site and a financial-data profile. The agent navigated FINRA’s BrokerCheck (a harder Angular app than the FDA’s form) to a broker-dealer’s authoritative regulatory record: firm name, CRD number, regulator, and disclosure count. It grounded on one retry.
From pharma to finance, the same pipeline worked with no code changes beyond the query and the schema. It should extend the same way to competitive pricing, market research, and product-safety monitoring. The data layer handles breadth and scale, the agent handles gated depth, and the agent’s fields are grounded against the live page.
From one record to a market
It also scales from one record to a market. We ran the identical pipeline across the GLP-1 drug market and got a structured competitive dataset. The data layer handled the breadth while the agent supplied each drug’s authoritative FDA record:
| Active ingredient | FDA brand | App # | Status | Top source (SERP) |
|---|---|---|---|---|
| semaglutide | OZEMPIC | 209637 | Prescription | drugs.com |
| tirzepatide | MOUNJARO | 215866 | Prescription | ncbi.nlm.nih.gov |
| liraglutide | LIRAGLUTIDE | 212552 | Prescription | drugs.com |
The market run even revealed a live discrepancy. Application 209637 read Discontinued in the single-record run above and Prescription in this table. An FDA application can hold several product records with different statuses, so each agent read is a snapshot of one row. That is exactly why you verify every read.
The unscripted reCAPTCHA
One moment we hadn’t scripted made the architecture’s case on its own. On two of the three lookups, the FDA site presented a reCAPTCHA to the agent.

The real reCAPTCHA the agent ran into on Drugs@FDA, captured mid-run. Nova Act’s guardrail refused to solve it. The session still reached the record, because it runs on Bright Data’s Browser API.
Nova Act’s guardrail refused to treat it as a puzzle to solve. From its trace, word for word, “I should not impersonate a human, or mis-direct being one by solving captchas or any other challenge.” That’s the behavior you want from an autonomous agent.
It still got through, because the session runs on Bright Data’s Browser API. A bare local browser couldn’t even load the FDA site. That browser timed out twice at 90 seconds, though it reached example.com fine in the same run. It reached neither the CAPTCHA nor the data. The Bright Data session reached the record.
So the division of labor is real and verified. The agent does not solve CAPTCHAs. It will not, and it should not. The data layer can’t navigate the form. Only the agent on Bright Data finishes the job.
The CAPTCHA is intermittent, and a later raw run had none. Those two CAPTCHA’d agent lookups took about 1m50s and 2m37s of real friction. The dataset is three rows, but the pattern holds for a whole market.
That’s Nova Act and Bright Data combined. Neither tool solves it alone.
Limitations
- Nova Act is still early. As of mid-2026 it’s a research preview, English-only, with a free tier that limits your interactions. It prints “Amazon collects data on interactions on this version” on every run. Production is AWS-coupled, with IAM, S3, and Bedrock AgentCore. Confirm production-tier terms and pricing with AWS before you build anything critical on it.
- The agent is fragile on popup-heavy consumer sites. On booking.com, the
ActActuationErrorwas the agent fighting the page, not Bright Data failing to serve it. Prefer direct result URLs, dismiss popups explicitly, rely on the retry budget, or offload to the data layer. - Compliance has two sides. It’s the guardrail you want, but restricted targets mean an account-manager or KYC step, so plan the lead time. And scraping-for-AI legality is contested in 2026, with landmark public-data rulings, the EU AI Act, and copyright suits still in progress. Public data isn’t automatic permission, so keep your legal team involved.
- Detection is an arms race. Agent fingerprinting and pay-per-crawl keep escalating. Staying ahead is continuous work, which is exactly why the layer is a managed dependency rather than a one-time fix.
- An autonomous browser is an attack surface. Pages can carry prompt-injection that steers the agent, and Nova Act’s own docs flag it. Limit it. Use URL allowlists and blocklists, and keep it off pages it doesn’t need. Drive sensitive input like credentials and payment through direct Playwright with
nova.page, instead of letting the model type it.
Next steps
Swap Nova Act for next year’s agent and the split still applies: the layer underneath is the durable part. So start by classifying the job, not the tool. If the target has a stable URL or a pre-built collector, send it to the data layer and skip the browser. Reserve Nova Act for what needs an action: a form to fill, a multi-step path, a portal with no scraper behind it.
For anything you plan to run more than once, set these from the first session:
- Move the zone’s inline credentials into an
Authorization: Basicheader, and add your IP to the zone allowlist. Skip either and you getInvalid URLor an empty body with the reason in the response headers. - Force a 1600×900 viewport on the connected page, and create
logs_directorybefore the run starts. - Ground every extracted field against
nova.pagein the same session, and budget 1.2 to 1.5× for retries.
When one zone stops keeping up, raise its concurrency limit before you blame the agent. Move bulk retrieval to the SERP API, Web Unlocker, or a Web Scraper API. The Browser API and Web MCP both ship with a free tier, so you can test the split before committing. Restricted targets are an account-manager conversation, not a workaround.
The runnable script for every demo here is in the companion repo. Clone it, point it at your own target, and see which half of the split your job actually needs.
Frequently asked questions
What is Amazon Nova Act?
Amazon Nova Act is an AWS SDK for building browser agents in Python. You break a workflow into small, reliable commands: act() for actions and act_get() for typed extraction. It drives a real Chromium through Playwright. As of mid-2026 it’s a research preview.
Does Nova Act work with Bright Data?
Yes, over the Chrome DevTools Protocol. Nova Act attaches to Bright Data’s Browser API through cdp_endpoint_url and cdp_headers. The setup catch is that modern Playwright rejects the inline-credential wss:// URL, so move the credentials into an Authorization: Basic header and force a 1600×900 viewport.
Can I use a proxy with Nova Act?
Not with the native proxy parameter when you connect over CDP. Nova Act raises ValidationFailed with the message Cannot specify a proxy when connecting over CDP. Connect to Bright Data’s Browser API over CDP instead, where unblocking, geo-routing, and CAPTCHA handling happen on Bright Data’s side.
Is Nova Act production-ready?
As of mid-2026 it’s a research preview, English-only, with a metered free tier. Production runs on AWS with IAM, S3, and Bedrock AgentCore. In our runs it was reliable on cooperative, structured sites and brittle on hostile consumer ones. Confirm production terms and pricing with AWS before you build on it.
What does it cost to run a browser agent this way?
Bright Data’s Browser API bills about $8/GB pay-as-you-go (mid-2026). A heavy page moved about 3.4 MB: roughly $27 per 1,000 pages before retries. Budget 1.2 to 1.5× on top. A light page is nearer $1.60 per 1,000. Nova Act’s inference isn’t publicly priced, so for bulk work use the data layer, not a browser.
Why not use my own headless browser and proxies?
The measured failure modes are only half the answer. Driving a browser is heavy, fragile on multi-step actuation, and non-deterministic. But the half that’s harder to run yourself is geography, compliance, and scale: an arms race that never ends. An infrastructure layer runs it so your engineering doesn’t have to.
When should I use the agent, not the data layer?
If the job is a fixed, known-schema pull, use a Web Scraper API, which returns the record with no page and no inference cost. If it needs reasoning that a scrape can’t capture (multi-step navigation, form submission, conditional logic), use the agent. In real systems the two compose.