<titledata-rh="true">Contributing | Puppeteer</title><metadata-rh="true"name="viewport"content="width=device-width,initial-scale=1"><metadata-rh="true"name="twitter:card"content="summary_large_image"><metadata-rh="true"property="og:url"content="https://pptr.dev/next/contributing"><metadata-rh="true"property="og:locale"content="en"><metadata-rh="true"name="docsearch:language"content="en"><metadata-rh="true"name="docsearch:counter"content="3"><metadata-rh="true"property="og:title"content="Contributing | Puppeteer"><metadata-rh="true"name="description"content="First of all, thank you for your interest in Puppeteer! We'd love to accept your"><metadata-rh="true"property="og:description"content="First of all, thank you for your interest in Puppeteer! We'd love to accept your"><linkdata-rh="true"rel="icon"href="/img/favicon.ico"><linkdata-rh="true"rel="canonical"href="https://pptr.dev/next/contributing"><linkdata-rh="true"rel="alternate"href="https://pptr.dev/next/contributing"hreflang="en"><linkdata-rh="true"rel="alternate"href="https://pptr.dev/next/contributing"hreflang="x-default"><linkdata-rh="true"rel="preconnect"href="https://DVKY664LG7-dsn.algolia.net"crossorigin="anonymous"><linkrel="search"type="application/opensearchdescription+xml"title="Puppeteer"href="/opensearch.xml">
<p>First of all, thank you for your interest in Puppeteer! We'd love to accept your
patches and contributions!</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="contributor-license-agreement">Contributor License Agreement<ahref="#contributor-license-agreement"class="hash-link"aria-label="Direct link to Contributor License Agreement"title="Direct link to Contributor License Agreement"></a></h2>
<p>Contributions to this project must be accompanied by a Contributor License
part of the project. Head over to <<ahref="https://cla.developers.google.com/"target="_blank"rel="noopener noreferrer">https://cla.developers.google.com/</a>> to see
your current agreements on file or to sign a new one.</p>
<p>You generally only need to submit a CLA once, so if you've already submitted one
<h2class="anchor anchorWithStickyNavbar_LWe7"id="getting-started">Getting started<ahref="#getting-started"class="hash-link"aria-label="Direct link to Getting started"title="Direct link to Getting started"></a></h2>
<p><ahref="https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=90796663&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json"target="_blank"rel="noopener noreferrer"><imgloading="lazy"src="https://github.com/codespaces/badge.svg"alt="Open in GitHub Codespaces"class="img_ev3q"></a></p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="building-a-single-package">Building a single package<ahref="#building-a-single-package"class="hash-link"aria-label="Direct link to Building a single package"title="Direct link to Building a single package"></a></h2>
<h3class="anchor anchorWithStickyNavbar_LWe7"id="watch-mode">Watch mode<ahref="#watch-mode"class="hash-link"aria-label="Direct link to Watch mode"title="Direct link to Watch mode"></a></h3>
<p>To continuously build a package, you can run:</p>
all dependencies will be build or rebuild (if needed).</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="removing-stale-artifacts">Removing stale artifacts<ahref="#removing-stale-artifacts"class="hash-link"aria-label="Direct link to Removing stale artifacts"title="Direct link to Removing stale artifacts"></a></h2>
<p>It's possible some generated artifacts (such as
<h2class="anchor anchorWithStickyNavbar_LWe7"id="comprehensive-testing">Comprehensive testing<ahref="#comprehensive-testing"class="hash-link"aria-label="Direct link to Comprehensive testing"title="Direct link to Comprehensive testing"></a></h2>
<p>Outside of <code>npm test</code>, there are several other
<h3class="anchor anchorWithStickyNavbar_LWe7"id="unit-tests">Unit tests<ahref="#unit-tests"class="hash-link"aria-label="Direct link to Unit tests"title="Direct link to Unit tests"></a></h3>
<p>Tests that only test code (without the running browser) are put next to the classes they test
and run using the Node test runner (requires Node 20+):</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="code-reviews">Code reviews<ahref="#code-reviews"class="hash-link"aria-label="Direct link to Code reviews"title="Direct link to Code reviews"></a></h2>
<p>All submissions, including submissions by project members, require review. We
<h2class="anchor anchorWithStickyNavbar_LWe7"id="code-style">Code Style<ahref="#code-style"class="hash-link"aria-label="Direct link to Code Style"title="Direct link to Code Style"></a></h2>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="project-structure">Project structure<ahref="#project-structure"class="hash-link"aria-label="Direct link to Project structure"title="Direct link to Project structure"></a></h2>
<p>The following is a description of the primary folders in Puppeteer:</p>
<ul>
<li><code>packages</code> contains all public source code.</li>
<li><code>test</code> contains all test source code.</li>
<li><code>tools</code> contains miscellaneous scripts that are used in building and etc.</li>
<li><code>tools/mocha-runner</code> - contains the source code for our test runner.</li>
</ul>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="api-guidelines">API guidelines<ahref="#api-guidelines"class="hash-link"aria-label="Direct link to API guidelines"title="Direct link to API guidelines"></a></h2>
<p>When authoring new API methods, consider the following:</p>
<ul>
<li>Expose as little information as needed. When in doubt, don’t expose new
information.</li>
<li>Methods are used in favor of getters/setters.<!---->
<ul>
<li>The only exception is namespaces, e.g. <code>page.keyboard</code> and <code>page.coverage</code></li>
</ul>
</li>
<li>All string literals must be small case. This includes event names and option
values.</li>
<li>Avoid adding "sugar" API (API that is trivially implementable in user-space)
<h2class="anchor anchorWithStickyNavbar_LWe7"id="commit-messages">Commit messages<ahref="#commit-messages"class="hash-link"aria-label="Direct link to Commit messages"title="Direct link to Commit messages"></a></h2>
<p>In particular, breaking changes should clearly be noted as “BREAKING CHANGE:” in
the commit message footer. Example:</p>
<divclass="codeBlockContainer_Ckt0 theme-code-block"style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><divclass="codeBlockContent_biex"><pretabindex="0"class="prism-code language-text codeBlock_bY9V thin-scrollbar"style="color:#393A34;background-color:#f6f8fa"><codeclass="codeBlockLines_e6Vv"><spanclass="token-line"style="color:#393A34"><spanclass="token plain">fix(page): fix page.pizza method</span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"style="display:inline-block"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain">This patch fixes page.pizza so that it works with iframes.</span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"style="display:inline-block"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain">Issues: #123, #234</span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"style="display:inline-block"></span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain">BREAKING CHANGE: page.pizza now delivers pizza at home by default.</span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain">To deliver to a different location, use the "deliver" option:</span><br></span><spanclass="token-line"style="color:#393A34"><spanclass="token plain"> `page.pizza({deliver: 'work'})`.</span><br></span></code></pre><divclass="buttonGroup__atx"><buttontype="button"aria-label="Copy code to clipboard"title="Copy"class="clean-btn"><spanclass="copyButtonIcons_eSgA"aria-hidden="true"><svgviewBox="0 0 24 24"class="copyButtonIcon_y97N"><pathfill="currentColor"d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svgviewBox="0 0 24 24"class="copyButtonSuccessIcon_LjdS"><pathfill="currentColor"d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="writing-documentation">Writing documentation<ahref="#writing-documentation"class="hash-link"aria-label="Direct link to Writing documentation"title="Direct link to Writing documentation"></a></h2>
<p>Documentation is generated from TSDoc comments via <code>npm run docs</code>. It is automatically
published to our documentation site on merge and gets versioned on release.</p>
<p>This means that you should not change the markdown in files <code>docs/api</code> manually.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="writing-tsdoc-comments">Writing TSDoc comments<ahref="#writing-tsdoc-comments"class="hash-link"aria-label="Direct link to Writing TSDoc comments"title="Direct link to Writing TSDoc comments"></a></h2>
<p>Each change to Puppeteer should be thoroughly documented using TSDoc comments.
<h2class="anchor anchorWithStickyNavbar_LWe7"id="running-the-documentation-site-locally">Running the documentation site locally<ahref="#running-the-documentation-site-locally"class="hash-link"aria-label="Direct link to Running the documentation site locally"title="Direct link to Running the documentation site locally"></a></h2>
<ol>
<li>At root, install all dependencies with <code>npm i --ignore-scripts</code>.</li>
<li>run <code>npm run docs</code> which will generate all the <code>.md</code> files on
<code>puppeteer/docs/api</code>.</li>
<li>run <code>npm i</code> in <code>puppeteer/website</code>.</li>
<li>run <code>npm start</code> in <code>puppeteer/website</code>.</li>
</ol>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="adding-new-dependencies">Adding new dependencies<ahref="#adding-new-dependencies"class="hash-link"aria-label="Direct link to Adding new dependencies"title="Direct link to Adding new dependencies"></a></h2>
<p>For all dependencies (both installation and development):</p>
<ul>
<li><strong>Do not add</strong> a dependency if the desired functionality is easily
implementable.</li>
<li>If adding a dependency, it should be well-maintained and trustworthy.</li>
</ul>
<p>A barrier for introducing new installation dependencies is especially high:</p>
<ul>
<li><strong>Do not add</strong> installation dependency unless it's critical to project
success.</li>
</ul>
<p>There are additional considerations for dependencies that are environment
<h2class="anchor anchorWithStickyNavbar_LWe7"id="testing-tips">Testing tips<ahref="#testing-tips"class="hash-link"aria-label="Direct link to Testing tips"title="Direct link to Testing tips"></a></h2>
<ul>
<li>Every feature should be accompanied by a test.</li>
<li>Every public api event/method should be accompanied by a test.</li>
<li>Tests should not depend on external services.</li>
<li>Tests should work on all three platforms: Mac, Linux and Win. This is
especially important for screenshot tests.</li>
</ul>
<p>If a test is expected to fail on certain configurations or became flaky, update
<h2class="anchor anchorWithStickyNavbar_LWe7"id="api-coverage">API Coverage<ahref="#api-coverage"class="hash-link"aria-label="Direct link to API Coverage"title="Direct link to API Coverage"></a></h2>
<p>Every public API method or event should be called at least once in tests. To
ensure this, the main <code>test</code> command runs coverage during testing.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="debugging-puppeteer">Debugging Puppeteer<ahref="#debugging-puppeteer"class="hash-link"aria-label="Direct link to Debugging Puppeteer"title="Direct link to Debugging Puppeteer"></a></h2>
<h3class="anchor anchorWithStickyNavbar_LWe7"id="debugging-puppeteer-tests-via-vscode">Debugging Puppeteer tests via VSCode<ahref="#debugging-puppeteer-tests-via-vscode"class="hash-link"aria-label="Direct link to Debugging Puppeteer tests via VSCode"title="Direct link to Debugging Puppeteer tests via VSCode"></a></h3>
<p>Copy the provided default <code>.vscode/launch.template.json</code> to <code>.vscode/launch.json</code> and then use the integrated VSCode debugger to debug test.</p>
<p>Remember to build test before launching via:</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="rolling-new-chrome-version">Rolling new Chrome version<ahref="#rolling-new-chrome-version"class="hash-link"aria-label="Direct link to Rolling new Chrome version"title="Direct link to Rolling new Chrome version"></a></h2>
<p>There is a <ahref="https://github.com/puppeteer/puppeteer/blob/main/.github/workflows/update-browser-pins.yml"target="_blank"rel="noopener noreferrer">GitHub action</a> that runs once per day.
The action has a manual trigger that can be found on the <ahref="https://github.com/puppeteer/puppeteer/actions/workflows/update-browser-pins.yml"target="_blank"rel="noopener noreferrer">Actions Tab</a>.</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id="manual-instructions">Manual instructions<ahref="#manual-instructions"class="hash-link"aria-label="Direct link to Manual instructions"title="Direct link to Manual instructions"></a></h3>
<p>You can run the <ahref="https://github.com/puppeteer/puppeteer/blob/main/tools/update_chrome_revision.mjs"target="_blank"rel="noopener noreferrer"><code>tools/update_chrome_revision.mjs</code></a> locally
and try see if any changes need to be committed.</p>
<blockquote>
<p>Note: You may need to run <code>node --experimental-fetch tools/update_chrome_revision.mjs</code> as the script relies on <code>fetch</code></p>
</blockquote>
<p>The following steps are manual version of the script above.</p>
<ol>
<li>Find a suitable Chrome <code>revision</code> and <code>version</code> via <ahref="https://googlechromelabs.github.io/chrome-for-testing/"target="_blank"rel="noopener noreferrer">https://googlechromelabs.github.io/chrome-for-testing/</a> or <ahref="https://chromiumdash.appspot.com/"target="_blank"rel="noopener noreferrer">https://chromiumdash.appspot.com/</a>.</li>
<li>Update <code>packages/puppeteer-core/src/revisions.ts</code> with the found <code>version</code>
number.</li>
<li>Update <code>versions.js</code> with the new Chrome-to-Puppeteer <code>version</code> mapping and
update <code>lastMaintainedChromeVersion</code> with the the next one in from the list.</li>
<li>Run <code>npm run check</code>. If it fails, update
<code>feat(chrome): roll to Chrome 90.0.4427.0 (r856583)</code>.</li>
</ol>
<blockquote>
<p>NOTE: Another place you can find version corresponding version is <ahref="https://omahaproxy.appspot.com/"target="_blank"rel="noopener noreferrer">omahaproxy.appspot.com</a> by
searching in <code>Find Releases</code> for <code>r<revision></code>.</p>
</blockquote>
<h3class="anchor anchorWithStickyNavbar_LWe7"id="bisecting-upstream-changes">Bisecting upstream changes<ahref="#bisecting-upstream-changes"class="hash-link"aria-label="Direct link to Bisecting upstream changes"title="Direct link to Bisecting upstream changes"></a></h3>
<p>For bisecting Chrome/Chromium changes use <ahref="https://www.chromium.org/developers/bisect-builds-py/"target="_blank"rel="noopener noreferrer">https://www.chromium.org/developers/bisect-builds-py/</a>.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="releasing-to-npm">Releasing to npm<ahref="#releasing-to-npm"class="hash-link"aria-label="Direct link to Releasing to npm"title="Direct link to Releasing to npm"></a></h2>
<p>We use <ahref="https://github.com/googleapis/release-please"target="_blank"rel="noopener noreferrer">release-please</a> to
our <ahref="https://github.com/puppeteer/puppeteer/pulls"target="_blank"rel="noopener noreferrer">pull requests</a> and merge it.</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id="in-case-release-please-fails">In case Release Please fails<ahref="#in-case-release-please-fails"class="hash-link"aria-label="Direct link to In case Release Please fails"title="Direct link to In case Release Please fails"></a></h3>
<p>In the event release-please fails, the following needs to be done:</p>
<ol>
<li>
<p>Update anything missing in the CHANGELOG of every package that was supposed
to be published. For example, if the header is missing, you may need to add</p>
<ul>
<li>
<p>For puppeteer:</p>
<divclass="language-md codeBlockContainer_Ckt0 theme-code-block"style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><divclass="codeBlockContent_biex"><pretabindex="0"class="prism-code language-md codeBlock_bY9V thin-scrollbar"style="color:#393A34;background-color:#f6f8fa"><codeclass="codeBlockLines_e6Vv"><spanclass="token-line"style="color:#393A34"><spanclass="token title important punctuation"style="color:#393A34">##</span><spanclass="token title important"> [{NEW_VERSION}](https://github.com/puppeteer/puppeteer/compare/v{PREVIOUS_VERSION}...v{NEW_VERSION}) ({CURRENT_DATE})`</span><br></span></code></pre><divclass="buttonGroup__atx"><buttontype="button"aria-label="Copy code to clipboard"title="Copy"class="clean-btn"><spanclass="copyButtonIcons_eSgA"aria-hidden="true"><svgviewBox="0 0 24 24"class="copyButtonIcon_y97N"><pathfill="currentColor"d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svgviewBox="0 0 24 24"class="copyButtonSuccessIcon_LjdS"><pathfill="currentColor"d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
<li>
<p>For other packages:</p>
<divclass="language-md codeBlockContainer_Ckt0 theme-code-block"style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><divclass="codeBlockContent_biex"><pretabindex="0"class="prism-code language-md codeBlock_bY9V thin-scrollbar"style="color:#393A34;background-color:#f6f8fa"><codeclass="codeBlockLines_e6Vv"><spanclass="token-line"style="color:#393A34"><spanclass="token title important punctuation"style="color:#393A34">##</span><spanclass="token title important"> [{NEW_VERSION}](https://github.com/puppeteer/puppeteer/compare/{PACKAGE_FOLDER_NAME}-v{PREVIOUS_VERSION}...{PACKAGE_FOLDER_NAME}-v{NEW_VERSION}) ({CURRENT_DATE})</span><br></span></code></pre><divclass="buttonGroup__atx"><buttontype="button"aria-label="Copy code to clipboard"title="Copy"class="clean-btn"><spanclass="copyButtonIcons_eSgA"aria-hidden="true"><svgviewBox="0 0 24 24"class="copyButtonIcon_y97N"><pathfill="currentColor"d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svgviewBox="0 0 24 24"class="copyButtonSuccessIcon_LjdS"><pathfill="currentColor"d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
</li>
</ul>
</li>
<li>
<p>Create a GitHub release for each package, following the practice of previous
releases.</p>
</li>
</ol>
<h2class="anchor anchorWithStickyNavbar_LWe7"id="bug-triage-guidelines">Bug triage guidelines<ahref="#bug-triage-guidelines"class="hash-link"aria-label="Direct link to Bug triage guidelines"title="Direct link to Bug triage guidelines"></a></h2>
<p><ahref="https://github.com/puppeteer/puppeteer/issues"target="_blank"rel="noopener noreferrer">Check incoming bug reports</a> that do not have a <code>confirmed</code> or <code>needs-feedback</code> label:</p>
<ol>
<li>Make sure the issue is labeled as either <code>bug</code> or <code>feature</code>.</li>
<li>If the issue does not have a clear repro or you cannot repro, ask for the repro and set the <code>needs-feedback</code> label.</li>
<li>Follow-up on the issues you previously asked for a feedback on (you should get a notification on GitHub when the user responds).</li>
<li>If the user does not provide feedback, the issue will be closed by the stale bot eventually.</li>
<li>If you are able to reproduce the issue, add the label <code>confirmed</code>.</li>
<li>If the bug is on the Chromium side, create a corresponding crbug.com issue, label the GitHub issue with the <code>upstream</code> label, and post a link to crbug.com in the comments.</li>
<li>If the issue is not related to either Puppeteer or Chromium, close the issue.</li>
<li>If the issue is about missing/incorrect documentation, label it as <code>documentation</code>.</li>
</ol>
<p>Issues with PDFs:</p>
<ol>
<li>If the issue reproduces using the regular print dialog and/or headful, <ahref="https://bugs.chromium.org/p/chromium/issues/entry?components=Blink%3ELayout"target="_blank"rel="noopener noreferrer">file a crbug.com against the <code>Blink>Layout</code> component</a>.</li>
<li>If the issue is specific to Headless mode, <ahref="https://bugs.chromium.org/p/chromium/issues/entry?components=Internals%3EHeadless"target="_blank"rel="noopener noreferrer">file an issue on crbug.com against the <code>Internals>Headless</code> component</a>.</li>