How to Screenshot Competitor Blog Pages and Compare Their Layouts
Capture competitor blog pages at matching sizes, then compare article structure with a repeatable checklist and visual matrix.
To compare competitor blog layouts, capture each page at the same viewport size, browser zoom, and page state. Use a viewport screenshot to compare the first screen, a full-page screenshot to compare the complete article flow, and an element screenshot when you want to study one component. Then record the same layout details for every page in a comparison matrix.
This process helps you identify structural patterns and design opportunities. A screenshot shows how a page looked at one moment; it does not reveal whether its design is accessible, performs well, or converts readers.
1. Choose comparable pages and define the question
Start with a small set of pages that serve a similar reader need and use a similar format. Comparing an article with a product landing page will usually produce observations that are hard to act on.
For each page, record its URL, page title, capture date, and why it belongs in the review. Decide what you want to learn before capturing: for example, how publishers handle the title and byline, where they place related content, or how the article page changes on mobile.
- Choose pages aimed at a similar audience or covering a similar subject.
- Keep the format comparable, such as long-form guides with other long-form guides.
- Capture desktop and mobile as separate conditions.
- Note whether a cookie notice, login state, or other overlay is visible.
2. Make capture conditions consistent
A useful comparison depends on matching the conditions as closely as practical. Use the same browser and viewport dimensions, keep browser zoom at the same level, and capture the same page state. Record the dimensions and browser used so you can repeat the review later.
For repeatable browser automation, Playwright supports viewport, element, and full-page screenshots. Its documentation defines a full-page screenshot as capturing the full scrollable page rather than just the current viewport. Playwright screenshots documentation
- Viewport: best for comparing the first screen, such as navigation, title, and opening image.
- Full page: best for the article’s overall flow, including lower-page calls to action and footer.
- Element: best for a specific component, such as a newsletter prompt or author box.
Keep the chosen browser, browser version, operating system, and headless or headed mode consistent when possible. Playwright notes that rendering can vary with the host operating system, browser version, settings, hardware, power source, and headless mode. A visual difference may come from the capture environment instead of a real layout change. Playwright visual comparisons documentation
3. Capture pages with Playwright
For a one-off review, use your browser’s screenshot capability or a screenshot tool. For a repeatable set of URLs and viewports, Playwright can automate the capture. The following JavaScript script opens each URL in Chromium, applies the same viewport, waits for the page to load, and saves a full-page PNG for each page.
Runnable setup
mkdir blog-layout-review
cd blog-layout-review
npm init -y
npm install playwright
npx playwright install chromium
Save this as capture.mjs. Replace the sample URLs with the pages you are reviewing.
import { chromium } from 'playwright';
import { mkdir } from 'node:fs/promises';
const pages = [
{ name: 'competitor-a', url: 'https://example.com/blog/article-a' },
{ name: 'competitor-b', url: 'https://example.org/blog/article-b' },
];
const width = 1440;
const height = 1000;
const browser = await chromium.launch({ headless: true });
await mkdir('screenshots', { recursive: true });
try {
const context = await browser.newContext({
viewport: { width, height },
deviceScaleFactor: 1,
reducedMotion: 'reduce',
});
for (const item of pages) {
const page = await context.newPage();
try {
const response = await page.goto(item.url, {
waitUntil: 'domcontentloaded',
timeout: 45_000,
});
await page.locator('body').waitFor({ state: 'visible', timeout: 10_000 });
await page.waitForTimeout(1_000);
await page.screenshot({
path: `screenshots/${item.name}-desktop.png`,
fullPage: true,
animations: 'disabled',
});
console.log(`${item.name}: HTTP ${response?.status() ?? 'no response'}`);
} catch (error) {
console.error(`${item.name}: ${error.message}`);
} finally {
await page.close();
}
}
await context.close();
} finally {
await browser.close();
}
Run it with node capture.mjs. A full-page screenshot captures the full scrollable page. If you only need the opening viewport, remove fullPage: true. For an element, use a locator such as await page.locator('article').screenshot({ path: 'article.png' }); choose a selector that matches the target on that site.
The script uses domcontentloaded rather than waiting for every network request to finish. Pages with slow or continuously active analytics, ads, or embedded media may never reach a network-idle state. The short fixed wait is a practical settling period, but inspect the result and increase or replace it if the page’s key content appears later.
Python option
Playwright also supports Python. Install the package and browser, then run this script to capture the same pages with a consistent viewport.
python -m pip install playwright
python -m playwright install chromium
import asyncio
from pathlib import Path
from playwright.async_api import async_playwright
PAGES = [
("competitor-a", "https://example.com/blog/article-a"),
("competitor-b", "https://example.org/blog/article-b"),
]
async def main():
Path("screenshots").mkdir(exist_ok=True)
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
context = await browser.new_context(
viewport={"width": 1440, "height": 1000},
device_scale_factor=1,
reduced_motion="reduce",
)
for name, url in PAGES:
page = await context.new_page()
try:
response = await page.goto(
url, wait_until="domcontentloaded", timeout=45_000
)
await page.locator("body").wait_for(
state="visible", timeout=10_000
)
await page.wait_for_timeout(1_000)
await page.screenshot(
path=f"screenshots/{name}-desktop.png", full_page=True
)
status = response.status if response else "no response"
print(f"{name}: HTTP {status}")
except Exception as error:
print(f"{name}: {error}")
finally:
await page.close()
await context.close()
await browser.close()
asyncio.run(main())
Capturing a mobile condition
Repeat the capture at a mobile viewport and save it as a separate screenshot set. For a simple responsive-width comparison in the JavaScript script, change the context viewport to a mobile width such as 390 by 844. Keep the browser and other settings the same. If you need device-specific rendering, use a Playwright device descriptor and note which one you selected; do not compare one site’s desktop capture with another site’s mobile capture.
4. Compare the same regions on every page
View captures side by side at the same display scale. For full-page screenshots, inspect the page in sections rather than shrinking the entire image until details are unreadable. Write down what is visible first, then add your interpretation separately.
| Area | What to record |
|---|---|
| Global frame | Header height, navigation density, background, page margins |
| Article identity | Title scale, subtitle, author and date placement, category labels |
| Reading column | Approximate width, line length, alignment, spacing between sections |
| Type hierarchy | Heading levels, body size, weight, line spacing |
| Media | Featured-image ratio and placement, captions, rhythm of in-article images |
| Supporting modules | Sidebar, table of contents, related posts, newsletter or product prompts |
| Page ending | Author box, related content, comments, footer, next-step prompts |
| Responsive behavior | Changes to navigation, columns, images, and prompts at mobile width |
A simple matrix turns observations into a working brief:
| Page | Viewport | Title/byline | Content width | Sidebar | Inline prompts | Footer | Notes |
|------|----------|--------------|---------------|---------|----------------|--------|-------|
| A | 1440x1000| | | | | | |
| B | 1440x1000| | | | | | |
| A | 390x844 | | | | | | |
| B | 390x844 | | | | | | |
Separate observation from interpretation. For example, write “a related-post card appears after the third section” as an observation. “This may help readers discover another article” is an interpretation. A screenshot cannot tell you whether that placement improves engagement or conversion.
5. Decide when a visual diff helps
For a small review, side-by-side inspection is often sufficient. A visual diff can help when you repeat captures over time or compare pages under tightly controlled conditions. Playwright Test supports screenshot assertions and compares captures with a reference image. Its documentation also explains that screenshots can differ across platforms, browsers, and rendering environments. Review apparent diffs instead of treating every changed pixel as a page redesign. Playwright’s visual comparison guide
Do not compare unlike states. Match viewport, browser, browser version, device scale, and page state as closely as you can. Dynamic dates, rotating promotions, animations, cookie notices, and asynchronously loaded content may create differences unrelated to the structural question you are studying.
6. Turn the comparison into design decisions
Summarize the recurring conventions, useful exceptions, and opportunities worth considering on your own site. Choose one or two changes to explore or test. Treat competitor patterns as evidence of what those pages look like, not proof that a particular layout performs well. Do not reproduce another publisher’s copy, branding, or images; use the comparison to understand structure and make your own design choices.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It can return an image or PDF from one GET request, with options for full-page capture, element selection, viewport presets, and more. See the ScreenshotNeo API documentation for available parameters.
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up free and capture 1,000 screenshots a month with no card.
Troubleshooting
| Problem | Likely cause | What to try |
|---|---|---|
| Navigation times out | The site is slow, blocks automation, or keeps network requests active. | Use domcontentloaded, as in the example, and give navigation a practical timeout. Check whether the screenshot contains the needed article content before changing the wait condition. |
| The screenshot is blank or missing article text | The page renders content after initial navigation or requires a client-side transition. | Wait for a visible article or heading locator instead of relying only on a generic delay. If needed, add a short settling wait after the target becomes visible. |
| A full-page capture is unexpectedly very tall or fails | Long pages, sticky elements, or unusual layouts can make full-page captures unwieldy. | Capture the viewport and key components separately, or compare article sections in several captures. |
| Images or embeds are missing | They may be lazy-loaded, delayed, blocked, or outside the current viewport. | Scroll through the page before taking a full-page capture, then wait for the important media to appear. Record any remaining difference rather than assuming the page has no media. |
| Pages look different despite matching dimensions | Browser, operating system, fonts, device scale, headless mode, or dynamic page content may differ. | Keep the capture environment stable and record it. Re-capture the pages in the same session and compare the same state. |
| Element screenshot selector matches nothing | The selector is not present on that page, or the component loads later. | Inspect the page structure, choose a site-specific selector, and wait for that locator to become visible before capturing. |
| Playwright says the browser executable is missing | The Playwright package is installed but its browser binary is not. | Run npx playwright install chromium for JavaScript or python -m playwright install chromium for Python. |
Performance, reliability, and cost
For a handful of pages, manual capture has almost no setup cost and is easy to inspect. Browser automation adds installation and runtime work, but makes the viewport and capture steps repeatable. Full-page images can be large, so capture only the extent needed for the question and use a consistent image format and scale.
Reliability comes mainly from controlling the capture environment and being explicit about page readiness. A page that loads successfully can still show a consent overlay, a delayed image, or a changing promotion. Preserve the capture date and state in your notes so a later reviewer knows what the screenshot represents.
Playwright is an open-source browser automation framework; the examples here use local browser capture. ScreenshotNeo is an API option for teams that want to send capture requests without installing browser automation locally. Its billing rules and plan prices are described above; choose based on capture volume and whether the API workflow is useful to your review.
FAQ
Should I use a full-page screenshot for every comparison?
No. Use it when the whole article flow matters. A viewport capture is easier to inspect for the first screen, and an element capture is more useful for a specific module.
Can screenshots tell me which competitor has the better blog design?
They can help you compare visible structure and consistency. They cannot establish accessibility, reader behavior, or business outcomes.
How should I compare mobile layouts?
Capture every page at the same mobile viewport and compare that set separately from desktop. Keep the browser and other capture conditions consistent.
Can I automate repeat comparisons with Playwright?
Yes. Playwright can capture screenshots, and Playwright Test can compare captures against reference images. Keep the environment stable and inspect differences for rendering noise as well as actual layout changes.


