[{"data":1,"prerenderedAt":686},["ShallowReactive",2],{"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0":3,"doc-\u002Fdocs\u002Fstart\u002Finstallation":17,"docs-nav":584,"nav-compare":674,"editor-1fslqcv":684},["Island",4],{"key":5,"result":6},"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0",{"head":7},{"style":8},[9,11,13,15],{"innerHTML":10},".site-footer[data-v-8bb1d4ae]{border-top:1px solid var(--line);background:var(--chrome);padding:var(--sp-8) var(--gutter) var(--sp-10);gap:var(--sp-6);flex-direction:column;display:flex}.links[data-v-8bb1d4ae]{gap:var(--sp-4);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));max-width:62rem;display:grid}.links a[data-v-8bb1d4ae]{align-items:flex-start;gap:var(--sp-3);padding:var(--sp-3);border-bottom:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel);color:var(--ink);border:1px solid var(--line);display:flex}.links a[data-v-8bb1d4ae]:focus-visible,.links a[data-v-8bb1d4ae]:hover{border-color:var(--line-strong)}.links[data-v-8bb1d4ae] .mark,.links[data-v-8bb1d4ae] .rf-mark{width:1.35rem;height:1.35rem;color:var(--dim);flex:none;margin-top:.1rem}.links a[data-v-8bb1d4ae]:hover .mark,.links a[data-v-8bb1d4ae]:hover .rf-mark{color:var(--red)}.links span[data-v-8bb1d4ae]{flex-direction:column;gap:2px;min-width:0;display:flex}.links b[data-v-8bb1d4ae]{font-family:var(--font-display);font-size:.85rem;font-weight:400}.links small[data-v-8bb1d4ae]{color:var(--faint);font-size:.78rem}.colophon[data-v-8bb1d4ae]{color:var(--faint);margin:0;font-size:.75rem}@supports (corner-shape:bevel){.links a[data-v-8bb1d4ae]{corner-shape:bevel}}",{"innerHTML":12},".mark[data-v-cc0d96a5]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":14},".mark[data-v-26f5673d]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":16},".rf-mark[data-v-26317b3e]{fill:currentColor;stroke:none;flex:none}",{"id":18,"title":19,"body":20,"description":575,"extension":576,"meta":577,"navigation":578,"order":230,"path":579,"section":580,"seo":581,"stem":582,"__hash__":583},"docs\u002Fdocs\u002Fstart\u002Finstallation.md","Installation",{"type":21,"value":22,"toc":553},"minimark",[23,27,35,40,45,48,51,54,58,63,67,95,103,110,128,135,139,142,147,150,164,168,171,174,180,206,217,233,236,240,243,261,275,279,282,285,291,295,298,303,307,310,333,336,340,343,346,364,380,399,427,430,433,453,456,459,467,470,473,477,480,490,495,504,508,524,542,549],[24,25,26],"p",{},"Browser is a Python library that drives Playwright running in Node.js, so\nsomething has to supply that Node.js. There are two ways to do it, and the only\nreal decision at install time is which.",[24,28,29,30,34],{},"Both need ",[31,32,33],"strong",{},"Python 3.10 or newer",", and both should be done in a virtual\nenvironment.",[36,37,39],"h2",{"id":38},"choose-a-route","Choose a route",[41,42],"doc-table",{":head":43,":rows":44},"[\"\",\"Without Node.js\",\"With Node.js\"]","[[\"`pip install`\",\"`robotframework-browser[bb]`\",\"`robotframework-browser`\"],[\"Then run\",\"`rfbrowser install`\",\"`rfbrowser init`\"],[\"Node.js from\",\"The wheel, already on disk after `pip`\",\"You, on the `PATH`\"],[\"Works on\",\"Linux x64\u002Farm64, Windows x64, macOS x64\u002Farm64\",\"Anywhere Python and Node.js both run\"],[\"Extra npm packages\",\"No — what ships is what you get\",\"Yes\"],[\"Leaves you `npm` and `npx`\",\"No\",\"Yes\"]]",[24,46,47],{},"Start on the left. It is fewer moving parts, and in an environment where\ninstalling Node.js means a ticket and a wait, it removes the whole conversation.",[24,49,50],{},"Go right when something in that column is yours: a platform with no wheel, a\nJavaScript extension that needs npm packages Browser does not ship, or an\nexisting Node toolchain you would rather Browser used.",[24,52,53],{},"The two are not exclusive and not a one-way door. They differ only in where the\nNode.js comes from — the keywords, the arguments and the behaviour are the same\neither way — so switching later costs an uninstall and a reinstall, not a\nrewrite.",[36,55,57],{"id":56},"without-nodejs","Without Node.js",[59,60,62],"h3",{"id":61},"install","Install",[64,65],"terminal-block",{":sessions":66},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"pip install \\\"robotframework-browser[bb]\\\"\",\"output\":[\"Successfully installed robotframework-browser-%%browser%% robotframework-browser-batteries-%%browser%%\"]}]},{\"shell\":\"powershell\",\"steps\":[{\"command\":\"py -m pip install \\\"robotframework-browser[bb]\\\"\",\"output\":[\"Successfully installed robotframework-browser-%%browser%% robotframework-browser-batteries-%%browser%%\"]}]}]",[24,68,69,70,74,75,82,83,86,87,90,91,94],{},"The ",[71,72,73],"code",{},"[bb]"," extra pulls in\n",[76,77,81],"a",{"href":78,"rel":79},"https:\u002F\u002Fpypi.org\u002Fproject\u002Frobotframework-browser-batteries\u002F",[80],"nofollow","robotframework-browser-batteries",",\na platform-specific wheel carrying an unmodified official Node.js build, the\ngRPC wrapper and its production Node dependencies. It is not a single packed\nbinary: it is a real ",[71,84,85],{},"node"," and a real ",[71,88,89],{},"node_modules",", installed into\n",[71,92,93],{},"site-packages\u002FBrowserBatteries\u002Fbin\u002F",".",[24,96,97,98,102],{},"Which Node.js that is moves with the library, so it is a fact about a release\nrather than about the package. The ",[76,99,101],{"href":100},"\u002Freleases","release notes"," say which Node.js\nthe BrowserBatteries wheel was built with — check there for the release you are\ninstalling.",[24,104,105,106,109],{},"The quotes are for zsh, which is the default shell on macOS and treats bare\nsquare brackets as a glob. ",[71,107,108],{},"bash"," and PowerShell do not need them and do not\nmind them.",[111,112,114],"doc-note",{"kind":113},"aside",[24,115,116,117,119,120,123,124,127],{},"Installing ",[71,118,81],{}," by name gets you the same two\npackages — it depends on the matching ",[71,121,122],{},"robotframework-browser"," — so an existing\nrequirements file spelling it that way is not wrong. ",[71,125,126],{},"robotframework-browser[bb]","\nis written from the side you are more likely to remember: the library, with\nbatteries.",[24,129,130,131,134],{},"The two packages are ",[31,132,133],{},"tied to one version"," and having them differ is not\nsupported. That is what the extra buys beyond a shorter line: pip resolves both\nfrom a single constraint, so they cannot drift apart.",[59,136,138],{"id":137},"where-there-is-a-wheel","Where there is a wheel",[24,140,141],{},"A wheel is published for each of these, and tagged so that pip declines to\ninstall it where the bundled Node.js could not start:",[41,143],{":head":144,":rows":145,":nowrap":146},"[\"Platform\",\"Architecture\",\"Needs at least\"]","[[\"Linux\",\"x64\",\"glibc 2.28 — Debian 10, RHEL 8, Ubuntu 20.04\"],[\"Linux\",\"arm64\",\"glibc 2.28 — Debian 10, RHEL 8, Ubuntu 20.04\"],[\"Windows\",\"x64\",\"Windows 10 or Windows Server 2016\"],[\"macOS\",\"x64\",\"macOS 13.5\"],[\"macOS\",\"arm64\",\"macOS 13.5\"]]","[0,1]",[24,148,149],{},"There is no musl wheel, and none for Windows on arm. Anywhere else, pip reports\nthat it found no matching distribution — which is the wheel tags doing their\njob, and the signal to use the other route.",[111,151,153],{"kind":152},"warning",[24,154,155,156,159,160,163],{},"macOS ",[31,157,158],{},"13.0 to 13.4"," is the one case the tags cannot catch. Node.js needs\n13.5, but pip only ever generates ",[71,161,162],{},"macosx_13_0_*"," tags, so the wheel installs\nand then the bundled Node.js fails to start. On those four versions, either\nupdate macOS or install Node.js yourself.",[59,165,167],{"id":166},"browser-binaries","Browser binaries",[24,169,170],{},"Playwright's browser builds are downloaded separately, because they are not in\nthe wheel:",[64,172],{":sessions":173},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser install\",\"output\":[\"Installing Playwright browser binaries…\"],\"status\":[{\"ok\":true,\"text\":\"chromium   downloaded\"},{\"ok\":true,\"text\":\"firefox    downloaded\"},{\"ok\":true,\"text\":\"webkit     downloaded\"}]}]},{\"shell\":\"powershell\",\"steps\":[{\"command\":\"py -m Browser.entry install\",\"output\":[\"Installing Playwright browser binaries…\"],\"status\":[{\"ok\":true,\"text\":\"chromium   downloaded\"},{\"ok\":true,\"text\":\"firefox    downloaded\"},{\"ok\":true,\"text\":\"webkit     downloaded\"}]}]}]",[24,175,176,177,94],{},"Three engines, a few hundred megabytes, once per environment. Name one to get\nonly that one — ",[71,178,179],{},"rfbrowser install firefox",[111,181,182],{"kind":152},[24,183,184,189,190,193,194,197,198,202,203,94],{},[31,185,186],{},[71,187,188],{},"rfbrowser init"," ",[31,191,192],{},"is not for this route."," It runs ",[71,195,196],{},"npm ci"," and stops with\n",[199,200,201],"em",{},"Couldn't execute npm. Please ensure you have node.js and npm installed and in\nPATH"," — which reads like a broken installation and is not one. On this route the\ncommand is ",[71,204,205],{},"rfbrowser install",[24,207,208,209,212,213,216],{},"You can also skip this step entirely. If you already have a Chromium-based\nbrowser — Chrome or Edge — you can drive that instead by passing a ",[71,210,211],{},"channel"," to\n",[71,214,215],{},"New Browser",", and download nothing:",[218,219,224],"pre",{"className":220,"code":221,"language":222,"meta":223,"style":223},"language-robot-repl shiki shiki-themes github-light github-dark","New Browser    chromium    channel=chrome\n","robot-repl","",[71,225,226],{"__ignoreMap":223},[227,228,231],"span",{"class":229,"line":230},"line",1,[227,232,221],{},[24,234,235],{},"That combination — wheels only, no binary download — is what makes this route\nwork on a machine with no route to the public internet at all.",[59,237,239],{"id":238},"verify","Verify",[64,241],{":sessions":242},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser --version\",\"output\":[\"Installed Browser library version is: \\\"%%browser%%\\\"\",\"Installed Robot Framework version: \\\"7.4.1\\\"\",\"Required Playwright is: \\\"%%playwrightBundled%%\\\"\"]}]}]",[24,244,245,246,249,250,253,254,257,258,260],{},"It reports the Playwright as ",[199,247,248],{},"Required"," rather than ",[199,251,252],{},"Installed"," here, because\nreading the installed version means asking ",[71,255,256],{},"npm",", and there is no ",[71,259,256],{}," on this\nroute. The number is the one that ships in the wheel either way.",[24,262,263,264,267,268,271,272,274],{},"Note what it does ",[31,265,266],{},"not"," report: the browser binaries. ",[71,269,270],{},"rfbrowser --version","\nstaying green says nothing about whether ",[71,273,205],{}," ever ran.",[59,276,278],{"id":277},"upgrading","Upgrading",[24,280,281],{},"Upgrade both packages together, then rebuild the Node side:",[64,283],{":sessions":284},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"pip install -U robotframework-browser robotframework-browser-batteries\"},{\"command\":\"rfbrowser clean-node\",\"output\":[\"Delete library node dependencies from …\u002FBrowserBatteries\u002Fbin\u002Fwrapper\u002Fnode_modules\"]},{\"command\":\"rfbrowser install\"}]}]",[24,286,287,290],{},[71,288,289],{},"clean-node"," removes the old Node dependencies and browser binaries. Skipping it\nleaves the previous release's binaries behind, and a Playwright that has moved on\ndoes not necessarily drive them.",[59,292,294],{"id":293},"uninstalling","Uninstalling",[64,296],{":sessions":297},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser clean-node\"},{\"command\":\"pip uninstall robotframework-browser robotframework-browser-batteries\"}]}]",[24,299,300,302],{},[71,301,289],{}," first, and in that order: it is what deletes the browser binaries,\nand once pip has removed the package there is nothing left that knows where they\nwere.",[36,304,306],{"id":305},"with-nodejs","With Node.js",[59,308,62],{"id":309},"install-1",[24,311,312,313,318,319,322,323,325,326,328,329,332],{},"Install ",[76,314,317],{"href":315,"rel":316},"https:\u002F\u002Fnodejs.org\u002Fen\u002Fdownload\u002F",[80],"Node.js"," first — at the time of\nwriting that is ",[31,320,321],{},"22, 24 or 26",", and each release states the lines it supports\nin its ",[76,324,101],{"href":100},". Make sure ",[71,327,256],{}," is on your ",[71,330,331],{},"PATH",". Then:",[64,334],{":sessions":335},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"pip install robotframework-browser\",\"output\":[\"Successfully installed robotframework-browser-%%browser%%\"]}]},{\"shell\":\"powershell\",\"steps\":[{\"command\":\"py -m pip install robotframework-browser\",\"output\":[\"Successfully installed robotframework-browser-%%browser%%\"]}]}]",[59,337,339],{"id":338},"node-dependencies-and-browser-binaries","Node dependencies and browser binaries",[24,341,342],{},"One command does both, and the library does not work until it has run:",[64,344],{":sessions":345},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser init\",\"output\":[\"Installing node dependencies...\",\"Installing browser binaries to 0\",\"rfbrowser init completed\"]}]},{\"shell\":\"powershell\",\"steps\":[{\"command\":\"py -m Browser.entry init\",\"output\":[\"Installing node dependencies...\",\"Installing browser binaries to 0\",\"rfbrowser init completed\"]}]}]",[24,347,348,351,352,355,356,359,360,363],{},[71,349,350],{},"init"," runs ",[71,353,354],{},"npm ci --omit=dev"," against the lockfile shipped in the package, then\ndownloads the browsers. Name engines to narrow the download —\n",[71,357,358],{},"rfbrowser init chromium firefox"," — or pass ",[71,361,362],{},"--skip-browsers"," to install the Node\ndependencies alone and take responsibility for the binaries yourself.",[111,365,366],{"kind":152},[24,367,368,189,372,374,375,377,378,94],{},[31,369,370],{},[71,371,205],{},[31,373,192],{}," It exists for installations that\nhave BrowserBatteries, and running it here does not install the Node\ndependencies ",[71,376,350],{}," is responsible for. On this route the command is\n",[71,379,188],{},[24,381,382,383,386,387,351,389,391,392,394,395,94],{},"Do not add npm packages to ",[71,384,385],{},"Browser\u002Fwrapper"," by hand either. ",[71,388,350],{},[71,390,196],{},"\nthere, which deletes ",[71,393,89],{}," and reinstalls exactly the shipped\nproduction dependencies, so anything you put there disappears at the next init\nor upgrade. Extensions that need their own packages are covered in\n",[76,396,398],{"href":397},"\u002Fdocs\u002Fextending\u002Fjavascript-extensions","JavaScript extensions",[111,400,401,424],{},[24,402,403,406,407,409,410,412,413,416,417,420,421,423],{},[31,404,405],{},"On Node.js 26 with npm 12",", ",[71,408,350],{}," needs two extra steps. npm 12 no longer\nruns post-install scripts unless they are approved, and several of Browser's\ndependencies use them. Run ",[71,411,188],{}," once, then\n",[71,414,415],{},"npm approve-scripts --allow-scripts-pending"," to list what is waiting, then\n",[71,418,419],{},"npm approve-scripts \u003Cpackage> \u003Cpackage>"," for the ones belonging to Browser —\nreview the list, because it covers every npm project on the machine, not only\nthis one — and run ",[71,422,188],{}," again.",[24,425,426],{},"This is a moving target and it is npm's, not ours. It does not arise without\nNode.js, where the dependencies are already built into the wheel.",[59,428,239],{"id":429},"verify-1",[64,431],{":sessions":432},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser --version\",\"output\":[\"Installed Browser library version is: \\\"%%browser%%\\\"\",\"Installed Robot Framework version: \\\"7.4.1\\\"\",\"Installed Playwright is: \\\"%%playwrightBundled%%\\\"\"]}]}]",[24,434,435,249,437,439,440,443,444,446,447,449,450,452],{},[199,436,252],{},[199,438,248],{}," means the number came from ",[71,441,442],{},"npm list"," in the\nwrapper directory — so a line reading ",[199,445,252],{}," is also evidence that ",[71,448,350],{},"\ngot as far as writing ",[71,451,89],{},". It still says nothing about the browser\nbinaries.",[59,454,278],{"id":455},"upgrading-1",[64,457],{":sessions":458},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"pip install -U robotframework-browser\"},{\"command\":\"rfbrowser clean-node\",\"output\":[\"Delete library node dependencies from …\u002FBrowser\u002Fwrapper\u002Fnode_modules\"]},{\"command\":\"rfbrowser init\"}]}]",[24,460,461,463,464,466],{},[71,462,289],{}," between the two is not optional housekeeping. ",[71,465,196],{}," reinstalls\nfrom the new lockfile, but the browser binaries from the previous release are\noutside its reach and stay until something deletes them.",[59,468,294],{"id":469},"uninstalling-1",[64,471],{":sessions":472},"[{\"shell\":\"bash\",\"steps\":[{\"command\":\"rfbrowser clean-node\"},{\"command\":\"pip uninstall robotframework-browser\"}]}]",[36,474,476],{"id":475},"behind-a-proxy-or-offline","Behind a proxy, or offline",[24,478,479],{},"Both routes reach the network, but for different things, and that is the whole\nof what changes here.",[24,481,482,483,485,486,489],{},"Without Node.js there is one download — the browser binaries — and it can be\navoided altogether by driving an installed Chrome or Edge through ",[71,484,211],{},".\nWheels themselves can travel by hand: ",[71,487,488],{},"pip download robotframework-browser-batteries","\non a connected machine gets you the pair, and they install from a directory on\nthe target with no index at all.",[24,491,492,493,94],{},"With Node.js there are two: npm resolving the wrapper's dependencies, and\nPlaywright fetching the binaries. Both have to work, and an internal npm\nregistry usually has to be configured before the first ",[71,494,350],{},[24,496,497,498,503],{},"The browser download itself is Playwright's, and so are the variables that steer\nit through a proxy, a custom certificate authority or an internal mirror. They\nreach Playwright unchanged from either route, and\n",[76,499,502],{"href":500,"rel":501},"https:\u002F\u002Fplaywright.dev\u002Fdocs\u002Fbrowsers#install-behind-a-firewall-or-a-proxy",[80],"Playwright documents them"," —\nwe deliberately do not copy the list, because a copy is wrong the day it changes.",[36,505,507],{"id":506},"never-install-into-the-system-python","Never install into the system Python",[111,509,510],{},[24,511,512,513,406,516,519,520,523],{},"Use a virtual environment — ",[71,514,515],{},"uv",[71,517,518],{},"venv"," or ",[71,521,522],{},"pyenv",", whichever your team already\nuses. Installing into the system Python needs root, writes browser binaries into\na directory you do not own, and is painful to unpick. You will also need to test\nagainst a second Python version sooner than you expect.",[24,525,526,527,530,531,534,535,519,538,541],{},"For Node.js on the second route, use a version manager for the same reason: ",[71,528,529],{},"n","\nor ",[71,532,533],{},"nvm"," on Linux and macOS, ",[71,536,537],{},"nvm-windows",[71,539,540],{},"nodist"," on Windows.",[24,543,544,545,94],{},"Where the files actually land, and what the two halves do at run time, is\n",[76,546,548],{"href":547},"\u002Fdocs\u002Fconcepts\u002Farchitecture","how Browser works",[550,551,552],"style",{},"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":223,"searchDepth":554,"depth":554,"links":555},2,[556,557,566,573,574],{"id":38,"depth":554,"text":39},{"id":56,"depth":554,"text":57,"children":558},[559,561,562,563,564,565],{"id":61,"depth":560,"text":62},3,{"id":137,"depth":560,"text":138},{"id":166,"depth":560,"text":167},{"id":238,"depth":560,"text":239},{"id":277,"depth":560,"text":278},{"id":293,"depth":560,"text":294},{"id":305,"depth":554,"text":306,"children":567},[568,569,570,571,572],{"id":309,"depth":560,"text":62},{"id":338,"depth":560,"text":339},{"id":429,"depth":560,"text":239},{"id":455,"depth":560,"text":278},{"id":469,"depth":560,"text":294},{"id":475,"depth":554,"text":476},{"id":506,"depth":554,"text":507},"The two ways to install Browser — with a bundled Node.js runtime, or with one you provide yourself — and how to upgrade and remove each.","md",{},true,"\u002Fdocs\u002Fstart\u002Finstallation","start",{"title":19,"description":575},"docs\u002Fstart\u002Finstallation","GbR9E5xjXsw8ZUl--vsUCRNiKw3tz6cRCokeJPUaTeA",[585,590,594,598,603,607,612,617,621,623,627,631,635,640,644,648,652,657,661,665,669,673],{"path":547,"title":586,"description":587,"section":588,"order":589},"How Browser works","Python, a Node process and Playwright — what runs where, and where the files land.","concepts",5,{"path":591,"title":592,"description":593,"section":588,"order":560},"\u002Fdocs\u002Fconcepts\u002Fassertions","Assertions","Almost every getter can assert, every assertion retries, and each return type allows different operators. The complete AssertionEngine reference.",{"path":595,"title":596,"description":597,"section":588,"order":230},"\u002Fdocs\u002Fconcepts\u002Fbrowser-context-page","Browser, context and page","The three layers Playwright is built on — and why a new context is the cheapest clean slate you will ever get.",{"path":599,"title":600,"description":601,"section":588,"order":602},"\u002Fdocs\u002Fconcepts\u002Flogging","Logging and debugging","Four places Browser tells you what happened — log.html, the Playwright log, traces and coverage.",6,{"path":604,"title":605,"description":606,"section":588,"order":554},"\u002Fdocs\u002Fconcepts\u002Fselectors","Finding elements","Which selector strategy to reach for, why the order matters, and how to chain across iframes and shadow DOM.",{"path":608,"title":609,"description":610,"section":588,"order":611},"\u002Fdocs\u002Fconcepts\u002Fwaiting","Waiting and promises","Most waiting is already done for you. This is the rest of it — Wait For Condition, and how to run keywords in parallel with Promise To.",4,{"path":613,"title":614,"description":615,"section":616,"order":589},"\u002Fdocs\u002Fextending\u002Fbrowser-as-a-base","Browser as a base","Own the Browser instance in your own library — what you get free, what one line restores, and what you build yourself.","extending",{"path":618,"title":619,"description":620,"section":616,"order":554},"\u002Fdocs\u002Fextending\u002Fjavascript-basics","Just enough JavaScript","The JavaScript you need to write extensions and Evaluate JavaScript, for people who write Python.",{"path":397,"title":398,"description":622,"section":616,"order":560},"Add keywords that run on the Node side with full Playwright access — and attach a debugger to them.",{"path":624,"title":625,"description":626,"section":616,"order":611},"\u002Fdocs\u002Fextending\u002Fpython-libraries","Your own Python library","Move business logic out of Robot Framework and keep Browser exactly as it is.",{"path":628,"title":629,"description":630,"section":616,"order":230},"\u002Fdocs\u002Fextending\u002Fpython-plugins","Python plugins","Add or replace keywords from Python, with access to the library's own API and to the Node side.",{"path":632,"title":633,"description":634,"section":616,"order":602},"\u002Fdocs\u002Fextending\u002Ftranslations","Translating keywords","Using a translation package to get keyword names and documentation in your language, and writing one for a language nobody has covered yet.",{"path":636,"title":637,"description":638,"section":639,"order":611},"\u002Fdocs\u002Fmobile\u002Fdevice-list","Every device descriptor","The full list of names Get Device accepts, with the viewport, pixel ratio, touch and engine each one sets — filterable and sortable.","mobile",{"path":641,"title":642,"description":643,"section":639,"order":554},"\u002Fdocs\u002Fmobile\u002Fdevices","Emulating a device","Device descriptors, what the six or seven properties they set actually change, and the one that emulation cannot give you.",{"path":645,"title":646,"description":647,"section":639,"order":230},"\u002Fdocs\u002Fmobile\u002Fresponsive","Testing responsive pages","Why a browser at a phone-sized viewport tests responsiveness properly, what emulation cannot tell you, and where real devices actually belong.",{"path":649,"title":650,"description":651,"section":639,"order":560},"\u002Fdocs\u002Fmobile\u002Ftouch","Touch, permissions and location","Tap and why it needs hasTouch, granting camera or notifications without a dialog, faking where the user is, and the gestures Browser has no keyword for.",{"path":653,"title":654,"description":655,"section":656,"order":560},"\u002Fdocs\u002Foperations\u002Fdocker","Running in Docker","The published Browser image, the four docker run flags that matter, and why running as root breaks Chromium.","operations",{"path":658,"title":659,"description":660,"section":656,"order":611},"\u002Fdocs\u002Foperations\u002Fdocker-images","Building your own image","Extending the published image with your dependencies, the version lock between Browser and Playwright, and using it as a CI job container.",{"path":662,"title":663,"description":664,"section":656,"order":554},"\u002Fdocs\u002Foperations\u002Fenvironment-variables","Environment variables","The variables that change how Browser behaves, which of them are safe in production, and the import parameters that should usually be preferred.",{"path":666,"title":667,"description":668,"section":656,"order":230},"\u002Fdocs\u002Foperations\u002Fnode-process","The Node process","Browser starts a Node process to talk to Playwright. What that costs, how to share one across parallel runs, and how to pass it Node flags.",{"path":670,"title":671,"description":672,"section":580,"order":554},"\u002Fdocs\u002Fstart\u002Fgetting-started","Getting started","Install Browser, write a first test, and run it.",{"path":579,"title":19,"description":575,"section":580,"order":230},[675,678,681],{"to":676,"label":677},"\u002Fwhy\u002Fvs-cypress","vs Cypress",{"to":679,"label":680},"\u002Fwhy\u002Fvs-playwright","vs Playwright Test",{"to":682,"label":683},"\u002Fwhy\u002Fvs-seleniumlibrary","vs SeleniumLibrary",[685],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">New Browser\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    chromium    channel=chrome\u003C\u002Fspan>\u003C\u002Fspan>",1787585238390]