ScreenshotNeo

BlogHow-to

How to Run Visual Regression Tests for a Django Website Built in India

Set up repeatable Playwright screenshot tests for Django, review visual changes safely, and choose a local or hosted workflow for your team.

By the ScreenshotNeo team4 October 20269 min read

Visual regression tests catch unintended changes by comparing a page rendered in a browser with a previously reviewed screenshot. For a Django site, a practical starting point is Playwright: run the site, visit a few important routes in a known state, and use Playwright Test’s screenshot assertion to create and compare baselines. Review the first screenshots before committing them, then review diffs before accepting any updates.

“Built in India” does not require a different testing method. Choose test data, browser coverage, and CI infrastructure to suit your project and team; the Django and Playwright guidance cited here does not establish India-specific testing requirements.

1. Choose representative pages and states

Start with a small set of high-value pages. A useful initial set might include:

  • The home page.
  • A representative listing and detail page.
  • A login page or another important form.
  • An authenticated page, if the site has one.

Add desktop and mobile captures where responsive layout matters. Django’s documentation describes Playwright browser tests and screenshot cases that can include mobile, RTL, dark, and high-contrast variants. Include only variants your site supports or needs.

Keep interaction and content assertions alongside screenshots. A screenshot can reveal a layout regression, but it is not a substitute for checking that a form submits or that a heading has the expected text.

2. Install Playwright and configure the Django server

This walkthrough uses Playwright Test with TypeScript. It is a convenient local-first setup for screenshot assertions. The test expects Django to be available at http://127.0.0.1:8000; you can let Playwright start the development server or start it yourself.

In the project directory, install Playwright Test and its browser:

npm init playwright@latest
npx playwright install chromium

If the project already has a Node package setup, install the test package and browser instead:

npm install --save-dev @playwright/test
npx playwright install chromium

Create or update playwright.config.ts. The optional webServer configuration starts Django for local runs and waits for it to respond. If your project uses a different settings module, environment file, or run command, adapt the command to match it.

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

export default defineConfig({
  testDir: './tests/visual',
  fullyParallel: false,
  retries: process.env.CI ? 1 : 0,
  reporter: process.env.CI ? 'list' : 'html',
  use: {
    baseURL: 'http://127.0.0.1:8000',
    browserName: 'chromium',
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
    headless: true,
    trace: 'retain-on-failure',
  },
  projects: [
    { name: 'desktop-chromium', use: { ...devices['Desktop Chrome'] } },
    // Add a mobile project only if mobile layout is in scope.
    // { name: 'mobile-chromium', use: { ...devices['iPhone 13'] } },
  ],
  webServer: {
    command: 'python manage.py runserver 127.0.0.1:8000 --noreload',
    url: 'http://127.0.0.1:8000',
    reuseExistingServer: !process.env.CI,
    timeout: 120_000,
  },
});

If Playwright should not start Django, remove webServer, start the server yourself, and keep the same base URL. In CI, run the tests against a dedicated test settings module or another controlled environment rather than relying on a developer’s local database.

3. Write a screenshot test

Create tests/visual/homepage.spec.ts. Replace the route and heading with selectors that exist in your application. The heading check illustrates a readiness condition: wait for meaningful page content before capturing.

import { test, expect } from '@playwright/test';

test('homepage matches its reviewed visual baseline', async ({ page }) => {
  await page.goto('/');
  await expect(page.getByRole('heading', { name: /welcome/i })).toBeVisible();
  await expect(page).toHaveScreenshot('homepage.png', {
    fullPage: true,
    animations: 'disabled',
  });
});

Run the test once to generate the baseline, then inspect it:

npx playwright test tests/visual/homepage.spec.ts --project=desktop-chromium

Playwright’s screenshot assertion compares subsequent renders against the stored reference. Treat the first image as a proposed baseline, not as automatically approved truth. Review it and commit the approved snapshot with the test. Add a Python test fixture or a deterministic database setup when the page depends on records, authentication, or permissions.

For an authenticated page, establish the intended account state before capturing. For example, use a test-only login helper, a seeded account, or a saved Playwright storage state that is created securely for CI. Do not commit real credentials or production session data.

4. Make screenshots repeatable

A screenshot diff is only useful when the rendering conditions are controlled. Keep the following stable between baseline creation and comparison:

  • Browser and environment: Pin the Playwright/browser version and use the same CI image and operating system for baseline generation and comparison.
  • Viewport and scale: Set viewport dimensions and device scale factor explicitly. A different viewport can change line wrapping, breakpoints, and page height.
  • Data and account state: Use deterministic records, permissions, locale, and authentication. Avoid records that change between runs.
  • Readiness: Wait for a meaningful selector and, where needed, fonts or essential assets. Avoid arbitrary sleeps unless a known transition requires one.
  • Animation: Disable animations for screenshot capture or wait for the intended final state.
  • Volatile content: Remove or narrowly mask timestamps, rotating promotions, randomized content, and uncontrolled embeds. Document exclusions so they do not hide real regressions.

Playwright notes that rendering can vary with host OS, browser version, settings, hardware, power source, and headless mode. Its guidance is to run tests in the same environment used to generate the baselines. If you intentionally test multiple browsers or operating systems, keep separate baselines for each configuration. Playwright visual comparisons.

5. Review diffs and update baselines deliberately

When a screenshot assertion fails, inspect the actual image and diff before changing the reference. Decide whether the change is a bug or an intended design update. If it is intended, update the baseline and review the resulting image before committing it:

npx playwright test --update-snapshots

Playwright supports a maxDiffPixels threshold to tolerate a small, justified difference. Keep the threshold narrow and explain why it exists; a loose threshold can conceal a real layout change. Its screenshot assertion also supports stylePath for applying a stylesheet during capture, which can help suppress known volatile content. Prefer fixing the source of nondeterminism where possible. Screenshot assertion options.

Do not make baseline refresh an automatic response to every failure. That turns a useful review point into a way to accept regressions without understanding them.

6. Run the suite locally and in CI

Use a package script so the command is consistent for the team:

{
  "scripts": {
    "test:visual": "playwright test tests/visual"
  }
}

Then run:

npm run test:visual

In CI, install the same dependencies and browser version used for the baseline, start Django with controlled settings and data, and run the same command. Store failure artifacts such as traces and screenshots so reviewers can diagnose a diff. Keep baseline files in version control so changes are reviewed alongside code.

Django’s own documentation demonstrates Playwright browser tests and screenshot examples for its admin interface. Adapt its setup to your project’s routes and test data rather than assuming an example route matches your application. Django unit test documentation.

7. Local baselines or a hosted review service?

Local Playwright snapshots are a reasonable starting point for a small team: the tests and reference images live with the code, and CI can run the same checks. Consider a hosted visual-testing workflow when you have a concrete need for shared diff review, managed rendering, or wider browser coverage.

Percy documents JavaScript and Python Playwright integrations. Its Python workflow uses the Percy CLI and Playwright integration package to run tests with a project token. Applitools documents a Playwright fixture and eyes.check() visual checkpoints with match settings and ignored regions. Confirm current Python and Playwright version support, browser coverage, data handling, CI fit, contractual terms, and pricing directly before selecting a service; those details can change. Percy Playwright Python integration · Applitools Playwright integration.

For this task, keep the comparison focused on visual testing workflows. ScreenshotNeo is a screenshot API and MCP server for developers; it is useful when you need clean page captures by API or from an AI agent, but it does not replace Playwright’s baseline assertion and diff review workflow.

8. Troubleshooting common failures

Symptom Likely cause Fix
Every screenshot differs in CI The OS, browser version, headless settings, fonts, or viewport differs from baseline generation. Pin the browser and CI image; use the same viewport, scale, and capture settings. Keep distinct baselines for intentional platform differences.
Text shifts or wraps differently A web font has not loaded, or the viewport/font environment changed. Wait for a meaningful ready state and fonts where necessary; use a fixed viewport and consistent font installation.
Only timestamps, ads, or embeds differ Live or randomized content is uncontrolled. Use deterministic fixtures, disable the source in test settings, or narrowly mask the specific region and document the reason.
The page is blank or incomplete The server is not ready, the route redirects, assets fail, or the test captured before content rendered. Check the server URL and response, assert the expected heading or landmark, and inspect the Playwright trace for failed requests.
Mobile snapshot has desktop layout The test is using a desktop viewport or device scale configuration. Add a mobile project with the intended device preset and generate a separate reviewed baseline.
Update command replaces many snapshots Rendering changed globally or the test environment drifted. Stop and identify the environment or shared stylesheet change before accepting updates. Review each changed image.
Threshold hides a visible issue maxDiffPixels is too permissive. Lower or remove the threshold and address unstable content at its source.

9. Performance, reliability, and cost

Keep the initial suite small and run only the key routes and states. Full-page screenshots and additional browsers increase work, so add them where they cover a real layout or user-flow risk. Reuse a stable test server and fixtures, and parallelize only after confirming that tests do not interfere through shared records or account state.

Reliability comes primarily from controlled rendering conditions and disciplined baseline review. Retries can help diagnose intermittent infrastructure issues, but they do not make flaky screenshots trustworthy. Track whether failures come from application changes, environment drift, or unstable third-party content.

The local Playwright workflow uses your own CI and browser setup; hosted visual services may add service costs and data-handling considerations. Compare the total cost and review workflow against your team’s actual needs. This research does not establish current service prices or terms.

Or skip the browser setup

If you need a clean screenshot of a page without installing and maintaining a browser test environment, ScreenshotNeo provides a website screenshot API and MCP server. Its API accepts one GET request and can return PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
  • Bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing; response headers identify the page verdict and billing status.
  • An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf.
  • The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

FAQ

Does visual regression testing require a special setup for a Django site built in India?

No India-specific setup is established by the Django and Playwright sources used here. Use the same repeatable browser testing practices and choose infrastructure that fits your team.

Should I screenshot every Django route?

Usually start with representative, high-value templates and important states. Expand when a route has distinct layout or user-flow risk.

Can screenshot tests prove that a page works?

No. Pair visual checks with assertions for text, navigation, forms, and behavior that matter to the application.

When should a team move from local snapshots to a hosted service?

When it has a specific need such as shared visual review or managed browser coverage, and the service’s current compatibility, terms, data handling, and cost fit the project.