[{"data":1,"prerenderedAt":569},["ShallowReactive",2],{"navigation_docs":3,"-guide-errors":88,"-guide-errors-surround":564},[4,48],{"title":5,"path":6,"stem":7,"children":8,"icon":47},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31,35,39,43],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Scrape","\u002Fguide\u002Fscrape","1.guide\u002F02.scrape",{"title":16,"path":17,"stem":18},"Screenshots and PDFs","\u002Fguide\u002Fcaptures","1.guide\u002F03.captures",{"title":20,"path":21,"stem":22},"Links and accessibility and extract","\u002Fguide\u002Freading","1.guide\u002F04.reading",{"title":24,"path":25,"stem":26},"Crawl and search","\u002Fguide\u002Fcrawl","1.guide\u002F05.crawl",{"title":28,"path":29,"stem":30},"Sessions","\u002Fguide\u002Fsessions","1.guide\u002F06.sessions",{"title":32,"path":33,"stem":34},"CLI","\u002Fguide\u002Fcli","1.guide\u002F07.cli",{"title":36,"path":37,"stem":38},"MCP and Pi and OMP","\u002Fguide\u002Fagents","1.guide\u002F08.agents",{"title":40,"path":41,"stem":42},"Errors","\u002Fguide\u002Ferrors","1.guide\u002F09.errors",{"title":44,"path":45,"stem":46},"Custom providers","\u002Fguide\u002Fcustom","1.guide\u002F10.custom","i-lucide-book-open",{"title":49,"path":50,"stem":51,"children":52,"icon":87},"Providers","\u002Fproviders","2.providers\u002F00.index",[53,55,59,63,67,71,75,79,83],{"title":54,"path":50,"stem":51},"Every provider",{"title":56,"path":57,"stem":58},"Steel","\u002Fproviders\u002Fsteel","2.providers\u002F01.steel",{"title":60,"path":61,"stem":62},"Browserbase","\u002Fproviders\u002Fbrowserbase","2.providers\u002F02.browserbase",{"title":64,"path":65,"stem":66},"Kernel","\u002Fproviders\u002Fkernel","2.providers\u002F03.kernel",{"title":68,"path":69,"stem":70},"Browserless","\u002Fproviders\u002Fbrowserless","2.providers\u002F04.browserless",{"title":72,"path":73,"stem":74},"Hyperbrowser","\u002Fproviders\u002Fhyperbrowser","2.providers\u002F05.hyperbrowser",{"title":76,"path":77,"stem":78},"Anchor","\u002Fproviders\u002Fanchor","2.providers\u002F06.anchor",{"title":80,"path":81,"stem":82},"Cloudflare","\u002Fproviders\u002Fcloudflare","2.providers\u002F07.cloudflare",{"title":84,"path":85,"stem":86},"Playwright","\u002Fproviders\u002Fplaywright","2.providers\u002F08.playwright","i-lucide-server",{"id":89,"title":40,"body":90,"description":557,"extension":558,"links":559,"meta":560,"navigation":155,"path":41,"seo":562,"stem":42,"__hash__":563},"docs\u002F1.guide\u002F09.errors.md",{"type":91,"value":92,"toc":551},"minimark",[93,118,317,322,382,386,430,434,498,515,518,522,536,544,547],[94,95,96,97,101,102,105,106,109,110,113,114,117],"p",{},"Failures from a vendor go through ",[98,99,100],"code",{},"normalizeError",", so a 401 from Steel and a 401 from Cloudflare are the same ",[98,103,104],{},"AuthError",", and nearly everything else the package throws extends ",[98,107,108],{},"BrowserError"," too. Catch the class, not the message. Nearly is the honest word: a few guards still throw a plain ",[98,111,112],{},"Error",", like a Playwright screenshot without a session or ",[98,115,116],{},"No configured provider supports …"," from the resolver, so keep a last branch that rethrows.",[119,120,125],"pre",{"className":121,"code":122,"language":123,"meta":124,"style":124},"language-ts shiki shiki-themes browsers browsers browsers","import { AuthError, RateLimitError, create } from \"@agntn\u002Fbrowsers\";\n\ntry {\n  await (await create(\"steel\")).scrape(\"https:\u002F\u002Fexample.com\");\n} catch (error) {\n  if (error instanceof RateLimitError) {\n    await new Promise((resolve) => setTimeout(resolve, error.retryAfter * 1000));\n  }\n  else if (error instanceof AuthError) console.error(`fix the key for ${error.provider}`);\n  else throw error;\n}\n","ts","",[98,126,127,150,157,166,202,214,232,259,265,300,311],{"__ignoreMap":124},[128,129,132,136,140,143,147],"span",{"class":130,"line":131},"line",1,[128,133,135],{"class":134},"skH_V","import",[128,137,139],{"class":138},"s38Sx"," { AuthError, RateLimitError, create } ",[128,141,142],{"class":134},"from",[128,144,146],{"class":145},"shU9J"," \"@agntn\u002Fbrowsers\"",[128,148,149],{"class":138},";\n",[128,151,153],{"class":130,"line":152},2,[128,154,156],{"emptyLinePlaceholder":155},true,"\n",[128,158,160,163],{"class":130,"line":159},3,[128,161,162],{"class":134},"try",[128,164,165],{"class":138}," {\n",[128,167,169,172,175,178,182,185,188,191,194,196,199],{"class":130,"line":168},4,[128,170,171],{"class":134},"  await",[128,173,174],{"class":138}," (",[128,176,177],{"class":134},"await",[128,179,181],{"class":180},"sK71F"," create",[128,183,184],{"class":138},"(",[128,186,187],{"class":145},"\"steel\"",[128,189,190],{"class":138},")).",[128,192,193],{"class":180},"scrape",[128,195,184],{"class":138},[128,197,198],{"class":145},"\"https:\u002F\u002Fexample.com\"",[128,200,201],{"class":138},");\n",[128,203,205,208,211],{"class":130,"line":204},5,[128,206,207],{"class":138},"} ",[128,209,210],{"class":134},"catch",[128,212,213],{"class":138}," (error) {\n",[128,215,217,220,223,226,229],{"class":130,"line":216},6,[128,218,219],{"class":134},"  if",[128,221,222],{"class":138}," (error ",[128,224,225],{"class":134},"instanceof",[128,227,228],{"class":180}," RateLimitError",[128,230,231],{"class":138},") {\n",[128,233,235,238,241,244,247,250,253,256],{"class":130,"line":234},7,[128,236,237],{"class":134},"    await",[128,239,240],{"class":134}," new",[128,242,243],{"class":138}," Promise((resolve) ",[128,245,246],{"class":134},"=>",[128,248,249],{"class":180}," setTimeout",[128,251,252],{"class":138},"(resolve, error.retryAfter ",[128,254,255],{"class":134},"*",[128,257,258],{"class":138}," 1000));\n",[128,260,262],{"class":130,"line":261},8,[128,263,264],{"class":138},"  }\n",[128,266,268,271,274,276,278,281,284,287,289,292,295,298],{"class":130,"line":267},9,[128,269,270],{"class":134},"  else",[128,272,273],{"class":134}," if",[128,275,222],{"class":138},[128,277,225],{"class":134},[128,279,280],{"class":180}," AuthError",[128,282,283],{"class":138},") console.",[128,285,286],{"class":180},"error",[128,288,184],{"class":138},[128,290,291],{"class":145},"`fix the key for ${",[128,293,294],{"class":145},"error.provider",[128,296,297],{"class":145},"}`",[128,299,201],{"class":138},[128,301,303,305,308],{"class":130,"line":302},10,[128,304,270],{"class":134},[128,306,307],{"class":134}," throw",[128,309,310],{"class":138}," error;\n",[128,312,314],{"class":130,"line":313},11,[128,315,316],{"class":138},"}\n",[318,319,321],"h2",{"id":320},"fix-the-call","Fix the call",[323,324,325,338],"table",{},[326,327,328],"thead",{},[329,330,331,335],"tr",{},[332,333,334],"th",{},"Class",[332,336,337],{},"When",[339,340,341,355,372],"tbody",{},[329,342,343,349],{},[344,345,346],"td",{},[98,347,348],{},"UnknownProviderError",[344,350,351,352],{},"The name isn't in the registry. ",[98,353,354],{},"Unknown provider: nope",[329,356,357,362],{},[344,358,359],{},[98,360,361],{},"InvalidInputError",[344,363,364,365,368,369],{},"The arguments contradict each other, like ",[98,366,367],{},"selector"," with ",[98,370,371],{},"fullPage: true",[329,373,374,379],{},[344,375,376],{},[98,377,378],{},"UnsupportedOperationError",[344,380,381],{},"The provider can't do it. Anchor asked to scrape",[318,383,385],{"id":384},"fix-the-setup","Fix the setup",[323,387,388,396],{},[326,389,390],{},[329,391,392,394],{},[332,393,334],{},[332,395,337],{},[339,397,398,410,420],{},[329,399,400,404],{},[344,401,402],{},[98,403,104],{},[344,405,406,407],{},"Key missing, or the vendor said 401. ",[98,408,409],{},"Missing API key for steel. Set STEEL_API_KEY",[329,411,412,417],{},[344,413,414],{},[98,415,416],{},"PaymentError",[344,418,419],{},"The vendor said 402 or 403. Usually a plan or a balance",[329,421,422,427],{},[344,423,424],{},[98,425,426],{},"NoProviderConfiguredError",[344,428,429],{},"No key set for anything and nothing registered to fall back on",[318,431,433],{"id":432},"wait-or-try-elsewhere","Wait, or try elsewhere",[323,435,436,444],{},[326,437,438],{},[329,439,440,442],{},[332,441,334],{},[332,443,337],{},[339,445,446,460,470,488],{},[329,447,448,453],{},[344,449,450],{},[98,451,452],{},"RateLimitError",[344,454,455,456,459],{},"A 429. ",[98,457,458],{},"retryAfter"," holds the seconds, and the message names which provider refused and why",[329,461,462,467],{},[344,463,464],{},[98,465,466],{},"TimeoutError",[344,468,469],{},"No answer in time. Says how long it waited and from where",[329,471,472,477],{},[344,473,474],{},[98,475,476],{},"HTTPError",[344,478,479,480,483,484,487],{},"Any other status. ",[98,481,482],{},"statusCode",", ",[98,485,486],{},"url"," and the vendor's reason",[329,489,490,495],{},[344,491,492],{},[98,493,494],{},"SessionNotFoundError",[344,496,497],{},"The session is gone, released or expired on the vendor's side",[94,499,500,501,483,504,483,507,510,511,514],{},"The package also exports ",[98,502,503],{},"EmptyUrlError",[98,505,506],{},"ScrapeNotSupportedError",[98,508,509],{},"SessionLimitError"," and ",[98,512,513],{},"NoProviderAvailableError",". Nothing built in throws them today, so don't write a catch for one. A provider of your own can still use them.",[94,516,517],{},"A rate limit and a timeout are different problems, and they come back as different classes. One says slow down, the other says nobody answered. Mixing them up is how an agent ends up hammering a vendor that already said please stop.",[318,519,521],{"id":520},"keys-never-leak-into-a-message","Keys never leak into a message",[94,523,524,525,510,528,531,532,535],{},"Errors carry the request URL, so you can see which vendor failed. Query params like ",[98,526,527],{},"token",[98,529,530],{},"api_key",", and a username or password in the URL, are replaced with ",[98,533,534],{},"[REDACTED]"," first:",[119,537,542],{"className":538,"code":540,"language":541,"meta":124},[539],"language-text","HTTP 400 from https:\u002F\u002Fchrome.browserless.io\u002Fscreenshot?token=%5BREDACTED%5D: Element not found on page! (requestId: …)\n","text",[98,543,540],{"__ignoreMap":124},[94,545,546],{},"That line is real, from a Browserless element screenshot of a selector the page didn't have. Only the request ID is cut.",[548,549,550],"style",{},"html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":124,"searchDepth":152,"depth":152,"links":552},[553,554,555,556],{"id":320,"depth":152,"text":321},{"id":384,"depth":152,"text":385},{"id":432,"depth":152,"text":433},{"id":520,"depth":152,"text":521},"Most failures are a typed BrowserError. Which class means fix the call and which means wait and which means try another provider","md",null,{"icon":561},"i-lucide-circle-alert",{"title":40,"description":557},"-23zYeWDyDNxc8x2K81PWG-GcFARQSiGH3CtCYw9l7U",[565,567],{"title":36,"path":37,"stem":38,"description":566,"children":-1},"Hand the browsers to a model. One MCP server and two extensions that call the same executors and answer with the same text",{"title":44,"path":45,"stem":46,"description":568,"children":-1},"Put your own backend behind create(). One class that implements BrowserProvider and one register() call",1790685118015]