ScreenshotNeo

BlogHow-to

How to Pass Authentication Cookies to Argos CI Browser Screenshots

Restore Playwright authentication before calling Argos’s screenshot helper. Choose saved browser state for login flows or inject a known test cookie directly.

By the ScreenshotNeo team4 October 20269 min read

To capture a page that requires login with Argos CI, authenticate the Playwright browser first, then call Argos’s screenshot helper with that authenticated page. For a normal login flow, save and reuse Playwright storageState; if you have a valid test cookie value, add it to the browser context before navigating. Argos captures the page state produced by Playwright; it is not where you configure your application’s login cookie.

This guide uses Playwright Test and the Argos Playwright integration. The examples use placeholder hosts and credentials: substitute your staging application’s real URL and provide secrets through your CI environment.

1. Choose how to provide authentication

Approach Use it when What it carries
Saved storageState A setup step can complete the normal login flow Cookies and supported browser storage, so the test does not have to hand-copy a session cookie
context.addCookies() You know a valid cookie value and its scope The cookies you explicitly provide; it will not supply other login state your app requires

Prefer saved state for a login-created session. It follows the same login flow as the application and avoids guessing which pieces of browser state are required. Direct cookie injection is useful for a controlled test session, but only if the application really accepts that cookie by itself.

2. Install and configure the Playwright and Argos integration

Install the packages in your project using the package manager and versions your repository already uses:

npm install --save-dev @playwright/test @argos-ci/playwright
npx playwright install

Configure an authentication setup project and make the screenshot project depend on it. This example is a complete minimal playwright.config.ts; merge the project settings into an existing config if your repository already defines browsers, reporters, or projects.

import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./tests",
  reporter: ["list", ["@argos-ci/playwright/reporter"]],
  projects: [
    {
      name: "setup",
      testMatch: /auth\.setup\.ts/,
    },
    {
      name: "chromium",
      use: {
        ...devices["Desktop Chrome"],
        storageState: "playwright/.auth/user.json",
      },
      dependencies: ["setup"],
      testIgnore: /auth\.setup\.ts/,
    },
  ],
});

Argos’s reporter uploads screenshot and trace artifacts in CI. Its upload credential is separate from the application cookie. Configure the Argos token as the ARGOS_TOKEN CI environment variable according to the Argos setup for your project. The Argos quickstart also describes GitHub Actions OIDC or tokenless authentication. The helper writes screenshots to ./screenshots by default; ignore that output directory and the generated auth state in version control.

Create tests/auth.setup.ts. Complete the same login flow your application expects, wait until the browser reaches a reliable authenticated state, then save the context state:

import { test as setup, expect } from "@playwright/test";

const authFile = "playwright/.auth/user.json";

setup("authenticate test account", async ({ page }) => {
  await page.goto("https://staging.example.com/login");
  await page.getByLabel("Email").fill(process.env.TEST_USER_EMAIL!);
  await page.getByLabel("Password").fill(process.env.TEST_USER_PASSWORD!);
  await page.getByRole("button", { name: "Sign in" }).click();

  // Wait for a stable authenticated signal used by your application.
  await expect(page).toHaveURL(/account/);
  await expect(page.getByRole("heading", { name: "Account" })).toBeVisible();

  await page.context().storageState({ path: authFile });
});

Replace the labels, success URL, and visible heading with selectors that match the app. Avoid saving immediately after clicking Sign in: the redirect, cookie assignment, or client-side initialization may not have finished. If authentication is confirmed by an API response or another stable page element, wait for that signal instead.

Add generated state and screenshot output to .gitignore:

playwright/.auth/
screenshots/

Keep the generated state out of the repository and handle it as a credential in CI. Playwright warns that a browser state file can contain sensitive cookies and headers capable of impersonating the test account. A practical pattern is to generate it in the CI job’s setup project rather than committing it. If your workflow transfers it as an artifact, restrict access and lifetime according to your CI security model.

4. Capture the authenticated page with Argos

In the dependent screenshot project, navigate to the protected page and pass the Playwright page to argosScreenshot:

import { test, expect } from "@playwright/test";
import { argosScreenshot } from "@argos-ci/playwright";

test("capture authenticated account page", async ({ page }) => {
  await page.goto("https://staging.example.com/account");
  await expect(page.getByRole("heading", { name: "Account" })).toBeVisible();
  await argosScreenshot(page, "account");
});

The configured project loads playwright/.auth/user.json when it creates the browser context. The screenshot helper captures that page; the reporter handles CI upload. A successful Argos upload does not prove that the application session was authenticated, so keep an assertion for an authenticated page signal before capturing.

Use this only when the test has a legitimate, known cookie value, such as a short-lived test session cookie provisioned for the job. Supply either a cookie url, or both domain and path. Match the application’s actual scope, security flags, and SameSite policy instead of copying guessed attributes.

import { test, expect } from "@playwright/test";
import { argosScreenshot } from "@argos-ci/playwright";

const cookieName = process.env.TEST_COOKIE_NAME;
const cookieValue = process.env.TEST_COOKIE_VALUE;

if (!cookieName || !cookieValue) {
  throw new Error("Set TEST_COOKIE_NAME and TEST_COOKIE_VALUE in the test environment");
}

test("capture page with injected test cookie", async ({ page }) => {
  await page.context().addCookies([
    {
      name: cookieName,
      value: cookieValue,
      url: "https://staging.example.com",
      httpOnly: true,
      secure: true,
      sameSite: "Lax",
    },
  ]);

  await page.goto("https://staging.example.com/account");
  await expect(page.getByRole("heading", { name: "Account" })).toBeVisible();
  await argosScreenshot(page, "account");
});

Cookie options include the required name and value plus a URL or domain and path. Expiry, httpOnly, secure, and sameSite are optional properties; use values appropriate to the app. A cookie scoped to the wrong host, path, or scheme will not be sent for the page request. Do not print cookie values to logs or include them in test failure messages.

6. Run it locally and in CI

  1. Set the test account credentials or cookie secret in the environment; do not put real values in source control.
  2. Run the setup and screenshot projects with your normal Playwright command, for example npx playwright test.
  3. Check the test assertion to confirm the page is authenticated before the screenshot helper runs.
  4. In CI, provide ARGOS_TOKEN (or configure the documented OIDC approach where applicable) so the reporter can upload.
  5. Keep generated playwright/.auth/ and screenshots/ out of Git.

Playwright project dependencies ensure the authentication setup runs before dependent screenshot tests. If your CI splits setup and capture into separate jobs, explicitly transfer the state through a protected, short-lived mechanism or repeat the login setup in the capture job. A local state file will not automatically exist on another runner.

7. Common errors and fixes

Symptom Likely cause Fix
The screenshot is a login page The screenshot project did not load the intended state, setup did not complete first, or the state expired Check the storageState path and project dependency; assert an authenticated page signal; regenerate the state through the login setup.
Injected cookie has no effect Cookie URL/domain/path does not match, it is expired, or the app needs more than that cookie Verify the actual cookie scope and expiry. Check whether the session also depends on local storage, IndexedDB, or another supported state mechanism; use saved state when the login flow creates multiple pieces of state.
Works locally but fails in CI The CI runner lacks the state file or required secrets, or the saved session expired or is invalid for the CI environment Generate auth state in the same job that captures, confirm secrets are present without printing them, and use a test account/session valid for the target environment.
Argos upload fails although the page is authenticated The Argos upload credential or reporter setup is missing; the app cookie is unrelated Configure the Argos reporter and its ARGOS_TOKEN or supported GitHub Actions OIDC flow. Do not use the application cookie as the upload token.
State is saved but a new tab or page is unauthenticated The application relies on state that is not in the saved file, or session storage requires special handling Check the app’s storage mechanism. Playwright state supports cookies, local storage, IndexedDB, and passkey authentication; session storage needs special handling in Playwright’s documentation.
Cookie appears in logs or an artifact Debug output or artifact collection exposed a credential Remove the logging, restrict artifact access, and rotate/revoke the test session if it may have been exposed.

8. Security, reliability, and performance

  • Use a dedicated test identity. A saved session or cookie can impersonate its account. Keep its permissions limited to the pages under test.
  • Plan for expiration. Login state can expire or be invalidated. Generate it as part of the CI run and make failures show a clear authentication assertion rather than silently accepting a login-page screenshot.
  • Keep setup deterministic. Wait for a final URL or stable authenticated element before saving state. Wait for the same kind of page readiness before capturing.
  • Reduce secret exposure. Do not commit state files or log cookie values; restrict CI secrets and any artifacts that contain state.
  • Keep setup scoped. Reusing state avoids repeating interactive login in every test, but a shared account can cause interference if tests mutate the same data. Use isolated test data or accounts where needed.

The main cost is the login/setup work and browser time in your CI job. Reusing state can avoid repeating the login flow for each screenshot test, while generating fresh state in the run avoids dependence on a stale committed session. Argos’s helper and reporter do not replace Playwright’s browser or application authentication.

9. If your test runner is Cypress

Do not use Playwright’s storageState or context.addCookies() APIs in Cypress. For a known cookie value, Cypress provides cy.setCookie(); for login-created cookies and web storage, use cy.session() to cache and restore session state. Cypress clears cookies and web storage between tests by default, so session setup matters. Argos has a Cypress integration with its own task registration and cy.argosScreenshot() API; follow that integration’s setup rather than the Playwright snippets above.

Or skip the browser setup

If you need a rendered screenshot without maintaining a Playwright browser job, ScreenshotNeo accepts a URL in one API request and returns an image or PDF. It does not use your Playwright login context: for private pages, use an authentication method supported by your own application and do not send credentials unless you have verified the request configuration is appropriate.

For a public page, the one-call request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with page verdict and billing headers on each response. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

No. Playwright’s browser context must be authenticated before the Argos helper captures its page.

Can I reuse one state file for several projects?

Yes, when those projects target the same app environment and the session remains valid. Ensure each project points to the intended file and protect it as a credential.

Can I use this to get around a login I do not control?

No. Use only an account and session you are authorized to test; screenshot capture records the browser’s state and does not grant access.

Official references