[{"data":1,"prerenderedAt":419},["ShallowReactive",2],{"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0":3,"doc-\u002Fdocs\u002Foperations\u002Fnode-process":17,"docs-nav":328,"nav-compare":401,"editor-1rdxt2f":411,"editor-1ipcy0m":413,"editor-89u7zy":415,"editor-ibk2pt":417},["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":319,"extension":320,"meta":321,"navigation":322,"order":87,"path":323,"section":324,"seo":325,"stem":326,"__hash__":327},"docs\u002Fdocs\u002Foperations\u002Fnode-process.md","The Node process",{"type":21,"value":22,"toc":310},"minimark",[23,27,30,36,41,44,60,64,70,73,114,121,148,151,169,191,194,199,202,239,242,246,251,257,276,282,285,289,306],[24,25,26],"p",{},"Browser is two halves. The Python half is the Robot Framework library you import;\nthe Node half drives Playwright. They talk over gRPC on a local port, and the\nPython half starts the Node half for you the first time you call a Browser\nkeyword.",[24,28,29],{},"Most of the time you never think about this. It matters in two situations: when\nyou run many suites in parallel, and when you need to debug the Node side itself.",[31,32,33],"doc-note",{},[24,34,35],{},"If none of that applies to you, you can skip this page. The default — one Node\nprocess per Robot Framework run, started and stopped automatically — is the right\nsetting for a normal suite.",[37,38,40],"h2",{"id":39},"what-the-startup-costs","What the startup costs",[24,42,43],{},"Starting the Node process is the slowest single step in a run: a process\nlaunch plus a gRPC health handshake, once per Robot Framework execution. It is\npaid at the first Browser keyword rather than at import — the library starts the\nprocess lazily — and on a single suite it disappears into the noise.",[24,45,46,47,54,55,59],{},"Under ",[48,49,53],"a",{"href":50,"rel":51},"https:\u002F\u002Fgithub.com\u002Fmkorpela\u002Fpabot",[52],"nofollow","Pabot"," it stops being noise. Pabot runs\neach suite in its own Robot Framework process, so ",[56,57,58],"strong",{},"each one starts its own Node\nprocess",". Twelve parallel suites means twelve Node processes, twelve startups,\nand twelve copies of the Playwright runtime resident at once.",[37,61,63],{"id":62},"sharing-one-node-process","Sharing one Node process",[31,65,67],{"kind":66},"warning",[24,68,69],{},"This is an experimental feature. It works, but it is not covered by the same\ncompatibility promise as the keywords, and the trade-offs below are real.",[24,71,72],{},"You can start the Node side yourself, once, and point every run at it. Start it\nfrom the directory where the Browser package is installed:",[74,75,80],"pre",{"className":76,"code":77,"language":78,"meta":79,"style":79},"language-bash shiki shiki-themes github-light github-dark","PLAYWRIGHT_BROWSERS_PATH=0 node Browser\u002Fwrapper\u002Findex.js 127.0.0.1 12345\n","bash","",[81,82,83],"code",{"__ignoreMap":79},[84,85,88,92,96,100,104,107,111],"span",{"class":86,"line":87},"line",1,[84,89,91],{"class":90},"sVt8B","PLAYWRIGHT_BROWSERS_PATH",[84,93,95],{"class":94},"szBVR","=",[84,97,99],{"class":98},"sZZnC","0",[84,101,103],{"class":102},"sScJk"," node",[84,105,106],{"class":98}," Browser\u002Fwrapper\u002Findex.js",[84,108,110],{"class":109},"sj4cs"," 127.0.0.1",[84,112,113],{"class":109}," 12345\n",[24,115,116,117,120],{},"The two arguments are the host and the port, in that order — both are\nrequired, and with only one the script exits with ",[81,118,119],{},"No port defined",". Then tell\nthe runs where to find it:",[74,122,124],{"className":76,"code":123,"language":78,"meta":79,"style":79},"ROBOT_FRAMEWORK_BROWSER_NODE_PORT=12345 pabot --processes 12 tests\u002F\n",[81,125,126],{"__ignoreMap":79},[84,127,128,131,133,136,139,142,145],{"class":86,"line":87},[84,129,130],{"class":90},"ROBOT_FRAMEWORK_BROWSER_NODE_PORT",[84,132,95],{"class":94},[84,134,135],{"class":98},"12345",[84,137,138],{"class":102}," pabot",[84,140,141],{"class":109}," --processes",[84,143,144],{"class":109}," 12",[84,146,147],{"class":98}," tests\u002F\n",[24,149,150],{},"The same thing can be said at import time instead, which is better when only some\nsuites should share and the rest should stay independent:",[74,152,156],{"className":153,"code":154,"language":155,"meta":79,"style":79},"language-robot shiki shiki-themes github-light github-dark","*** Settings ***\nLibrary    Browser    playwright_process_port=12345\n","robot",[81,157,158,163],{"__ignoreMap":79},[84,159,160],{"class":86,"line":87},[84,161,162],{},"*** Settings ***\n",[84,164,166],{"class":86,"line":165},2,[84,167,168],{},"Library    Browser    playwright_process_port=12345\n",[24,170,171,172,175,176,179,180,183,184,187,188,190],{},"There is a matching ",[81,173,174],{},"playwright_process_host",", which defaults to ",[81,177,178],{},"127.0.0.1",".\nOn its own it only changes the address the spawned process binds to; combined\nwith a port it is the address the library connects to. If both port settings are\nset the ",[56,181,182],{},"import parameter wins",": the\nport from ",[81,185,186],{},"playwright_process_port"," is checked first and the variable is only a\nfallback. There is no environment variable for the host — that is\n",[81,189,174],{}," only.",[24,192,193],{},"The environment variable is the blunt instrument — it\napplies to everything in that shell — and the import parameter is the precise one.",[195,196,198],"h3",{"id":197},"what-you-give-up","What you give up",[24,200,201],{},"Sharing genuinely removes that startup from every run but the first. It also means:",[203,204,205,212,227,233],"ul",{},[206,207,208,211],"li",{},[56,209,210],{},"One failure domain."," If the shared process dies, every run pointed at it\nfails, not just the one that killed it.",[206,213,214,217,218,222,223,226],{},[56,215,216],{},"Teardown is per connection, not global."," A finishing run closes the\nbrowsers ",[219,220,221],"em",{},"it"," opened. The Node side keeps separate state per client\nconnection, so other runs on the same process are untouched — runs only share\nstate if they deliberately call ",[81,224,225],{},"Set Peer Id"," with the same value.",[206,228,229,232],{},[56,230,231],{},"You own its lifecycle."," Nothing starts it for you and nothing cleans it up.\nIn CI that means a start step, a wait, and a teardown that runs even when the\nsuite fails.",[206,234,235,238],{},[56,236,237],{},"Debugging gets harder."," Logs from twelve suites interleave in one process.",[24,240,241],{},"Measure before you adopt it. If your suite takes four minutes and startup takes\ntwo seconds, this is not your bottleneck — and a shared process is a new thing\nthat can break in exchange for nothing.",[37,243,245],{"id":244},"passing-node-flags","Passing Node flags",[31,247,248],{"kind":66},[24,249,250],{},"Also experimental, and a development tool rather than a production one.",[24,252,253,256],{},[81,254,255],{},"ROBOT_FRAMEWORK_BROWSER_NODE_DEBUG_OPTIONS"," is passed through to the Node process\nas command-line arguments. Multiple arguments are separated by commas — not\nspaces, which is the mistake to expect:",[74,258,260],{"className":76,"code":259,"language":78,"meta":79,"style":79},"ROBOT_FRAMEWORK_BROWSER_NODE_DEBUG_OPTIONS=--inspect,--trace-warnings robot tests\u002F\n",[81,261,262],{"__ignoreMap":79},[84,263,264,266,268,271,274],{"class":86,"line":87},[84,265,255],{"class":90},[84,267,95],{"class":94},[84,269,270],{"class":98},"--inspect,--trace-warnings",[84,272,273],{"class":102}," robot",[84,275,147],{"class":98},[24,277,278,281],{},[81,279,280],{},"--inspect"," opens the Node inspector, so you can attach Chrome DevTools or an IDE\ndebugger to the Playwright side. That is occasionally the only way to understand\na failure that looks impossible from the Robot Framework log.",[24,283,284],{},"Keep it out of production runs. An open inspector port is a debugging affordance,\nnot something you want on a CI runner.",[37,286,288],{"id":287},"where-to-look-next","Where to look next",[203,290,291,299],{},[206,292,293,294,298],{},"The full list of variables that affect the Node process is on\n",[48,295,297],{"href":296},"\u002Fdocs\u002Foperations\u002Fenvironment-variables","Environment variables",".",[206,300,301,302,298],{},"How the two halves fit together, and why the library is built this way, is on\n",[48,303,305],{"href":304},"\u002Fdocs\u002Fconcepts\u002Farchitecture","How Browser works",[307,308,309],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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":79,"searchDepth":165,"depth":165,"links":311},[312,313,317,318],{"id":39,"depth":165,"text":40},{"id":62,"depth":165,"text":63,"children":314},[315],{"id":197,"depth":316,"text":198},3,{"id":244,"depth":165,"text":245},{"id":287,"depth":165,"text":288},"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.","md",{},true,"\u002Fdocs\u002Foperations\u002Fnode-process","operations",{"title":19,"description":319},"docs\u002Foperations\u002Fnode-process","y2mFiG8-ebqgxo557mN3Bi1fzw5fl89okmvKshQd_9g",[329,333,337,341,346,350,355,360,364,368,372,377,381,385,389,393,395,396],{"path":304,"title":305,"description":330,"section":331,"order":332},"Python, a Node process and Playwright — what runs where, and which installation to choose.","concepts",5,{"path":334,"title":335,"description":336,"section":331,"order":316},"\u002Fdocs\u002Fconcepts\u002Fassertions","Assertions","Almost every getter can assert, every assertion retries, and each return type allows different operators. The complete AssertionEngine reference.",{"path":338,"title":339,"description":340,"section":331,"order":87},"\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":342,"title":343,"description":344,"section":331,"order":345},"\u002Fdocs\u002Fconcepts\u002Flogging","Logging and debugging","Four places Browser tells you what happened — log.html, the Playwright log, traces and coverage.",6,{"path":347,"title":348,"description":349,"section":331,"order":165},"\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":351,"title":352,"description":353,"section":331,"order":354},"\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":356,"title":357,"description":358,"section":359,"order":165},"\u002Fdocs\u002Fextending\u002Fjavascript-basics","Just enough JavaScript","The JavaScript you need to write extensions and Evaluate JavaScript, for people who write Python.","extending",{"path":361,"title":362,"description":363,"section":359,"order":316},"\u002Fdocs\u002Fextending\u002Fjavascript-extensions","JavaScript extensions","Add keywords that run on the Node side with full Playwright access — and attach a debugger to them.",{"path":365,"title":366,"description":367,"section":359,"order":87},"\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":369,"title":370,"description":371,"section":359,"order":354},"\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":373,"title":374,"description":375,"section":376,"order":165},"\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.","mobile",{"path":378,"title":379,"description":380,"section":376,"order":87},"\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":382,"title":383,"description":384,"section":376,"order":316},"\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":386,"title":387,"description":388,"section":324,"order":316},"\u002Fdocs\u002Foperations\u002Fdocker","Running in Docker","The published Browser image, the four docker run flags that matter, and why running as root breaks Chromium.",{"path":390,"title":391,"description":392,"section":324,"order":354},"\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":296,"title":297,"description":394,"section":324,"order":165},"The variables that change how Browser behaves, which of them are safe in production, and the import parameters that should usually be preferred.",{"path":323,"title":19,"description":319,"section":324,"order":87},{"path":397,"title":398,"description":399,"section":400,"order":87},"\u002Fdocs\u002Fstart\u002Fgetting-started","Getting started","Install Browser, write a first test, and run it.","start",[402,405,408],{"to":403,"label":404},"\u002Fwhy\u002Fvs-cypress","vs Cypress",{"to":406,"label":407},"\u002Fwhy\u002Fvs-playwright","vs Playwright Test",{"to":409,"label":410},"\u002Fwhy\u002Fvs-seleniumlibrary","vs SeleniumLibrary",[412],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86B\">PLAYWRIGHT_BROWSERS_PATH\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">0\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> node\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> Browser\u002Fwrapper\u002Findex.js\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 127.0.0.1\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 12345\u003C\u002Fspan>\u003C\u002Fspan>",[414],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86B\">ROBOT_FRAMEWORK_BROWSER_NODE_PORT\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">12345\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> pabot\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> --processes\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 12\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> tests\u002F\u003C\u002Fspan>\u003C\u002Fspan>",[416],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E;font-weight:bold\">*** Settings ***\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">Library\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    Browser\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    playwright_process_port=12345\u003C\u002Fspan>\u003C\u002Fspan>",[418],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFB86B\">ROBOT_FRAMEWORK_BROWSER_NODE_DEBUG_OPTIONS\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\">=\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">--inspect,--trace-warnings\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> robot\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> tests\u002F\u003C\u002Fspan>\u003C\u002Fspan>",1786734139142]