How to Target HTML Elements When Capturing a Web Page
Choose a stable locator, confirm it matches the intended element, and capture that element with Playwright or Selenium.
To target an HTML element when capturing a web page, first identify it with a locator, then call the screenshot method on that locator. In Playwright, for example, page.getByRole('button', { name: 'Save' }).screenshot() captures the button. Use a page screenshot with fullPage: true when you want the scrollable page instead. Extracting HTML is a separate operation.
This guide focuses on DOM element screenshots with Playwright and Selenium. It covers choosing a locator, avoiding ambiguous matches, capturing a full page when appropriate, and diagnosing common failures. If you meant CSS :target, that is different: it refers to the element identified by the URL fragment, such as #setup. See MDN’s :target reference.
1. Decide what you want to capture
Choose the output before choosing the selector:
- One element: use a locator’s screenshot method. The result is cropped to the element’s bounds.
- The entire scrollable page: use the page screenshot API’s full-page option.
- The element’s markup or text: read its HTML or text content. A screenshot does not export HTML.
Playwright documents both locator screenshots and page screenshots in its Page API. A locator identifies the element; the screenshot call determines the captured output.
2. Choose a locator that describes the intended element
Prefer locators that express the element’s meaning or an explicit testing contract. Playwright recommends user-facing locators such as roles, labels, text, and alternative text, followed by test IDs where appropriate. Selenium recommends a unique, predictable ID when one is available, then a focused CSS selector. Both approaches help avoid brittle selectors tied to incidental page structure.
| Locator strategy | Good fit | Watch for |
|---|---|---|
| Role and accessible name | Buttons, links, headings, and other accessible elements | The accessible name must identify the intended target. |
| Label | Form controls associated with a label | Some custom controls may not expose a usable label. |
| Text | Content with distinctive visible text | Text changes, localization, or repeated text can make it unstable or ambiguous. |
| Alt text | Images with meaningful alternative text | Decorative images may have empty alt text. |
| Test ID | A deliberate, stable testing contract exposed by the site | Use a test ID only when the page provides one for this purpose. |
| ID or CSS selector | A unique, predictable ID or a compact selector based on meaningful attributes | Long chains of ancestors and incidental classes are fragile. |
| XPath | A focused query when it expresses the needed relationship clearly | Complex XPath can be difficult to debug and maintain. |
For a control, start with its role and accessible name. For non-interactive content, use distinctive text, a test ID, or a focused CSS selector. If the target appears multiple times, narrow the locator using a meaningful parent region or attribute instead of selecting the first match by default.
Playwright’s locator guidance explains its recommended locator priorities, strictness, and why long CSS or XPath chains tied to DOM structure are brittle. Selenium’s locator guidance discusses IDs, CSS selectors, and XPath.
3. Capture one element with Playwright
Here is a complete Node.js example. It opens a page, waits for a semantic locator, saves the element screenshot, and closes the browser even if capture fails.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
try {
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const heading = page.getByRole('heading', { name: 'Example Domain' });
await heading.waitFor({ state: 'visible' });
await heading.screenshot({ path: 'heading.png' });
} finally {
await browser.close();
}
Install Playwright and its browser before running the script:
npm install playwright
npx playwright install chromium
node capture-element.mjs
Save the code as capture-element.mjs. Replace the example URL and heading name with the page and target you need. For a selector exposed by the site, a locator can also be written as page.locator('[data-testid="pricing-card"]').
Check uniqueness before capture
Playwright’s single-element actions are strict: if a locator matches more than one element, the action fails instead of silently guessing. You can inspect the count while developing:
const card = page.getByTestId('pricing-card');
const matches = await card.count();
if (matches !== 1) {
throw new Error(`Expected one pricing card, found ${matches}`);
}
await card.screenshot({ path: 'pricing-card.png' });
When more than one match is expected, scope the locator to a meaningful parent:
const pricing = page.getByRole('region', { name: 'Pricing' });
const starterCard = pricing.getByRole('article').filter({ hasText: 'Starter' });
await starterCard.screenshot({ path: 'starter-card.png' });
Only use first(), last(), or nth() if position is part of the intended rule and remains meaningful when the page changes. Playwright locators are resolved when used, which helps when a page re-renders, but it cannot make an unstable selector meaningful.
4. Capture an element with Selenium in Python
If your workflow uses Selenium, locate the element and call screenshot on the resulting WebElement. This runnable example uses an ID, which is suitable when that ID is unique and predictable:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
options = webdriver.ChromeOptions()
options.add_argument('--headless=new')
driver = webdriver.Chrome(options=options)
try:
driver.set_window_size(1280, 900)
driver.get('https://example.com')
target = WebDriverWait(driver, 15).until(
EC.visibility_of_element_located((By.ID, 'target-element'))
)
if not target.screenshot('element.png'):
raise RuntimeError('Element screenshot was not saved')
finally:
driver.quit()
Install Selenium with python -m pip install selenium, save the script as capture_element.py, and run python capture_element.py. Selenium Manager can manage the browser driver for supported setups; consult the Selenium documentation for installation and browser-specific details. Replace target-element with the page’s actual ID. If no suitable ID exists, use a focused CSS selector such as [data-testid="pricing-card"]:
target = WebDriverWait(driver, 15).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '[data-testid="pricing-card"]'))
)
Use a locator strategy available in your Selenium language binding and keep the selector tied to meaningful attributes. If several elements match, narrow the search to a parent element or a more specific attribute. Selenium notes that XPath is supported, but its syntax can be difficult to debug.
5. Capture the full page or extract HTML instead
In Playwright, a page screenshot with fullPage: true captures the full scrollable page rather than just one element. This example saves both a viewport screenshot and a full-page screenshot:
await page.screenshot({ path: 'viewport.png' });
await page.screenshot({ path: 'full-page.png', fullPage: true });
If you want markup rather than pixels, read the target’s content separately:
const card = page.getByTestId('pricing-card');
const html = await card.evaluate(element => element.outerHTML);
const text = await card.innerText();
console.log({ html, text });
In Selenium, driver.save_screenshot('page.png') captures a page screenshot, while element.screenshot('element.png') captures one element. To read the element’s markup, use target.get_attribute('outerHTML'). These are distinct operations; choose based on whether you need an image, markup, or text.
6. Make the capture predictable
- Wait for the target: use a locator wait for visible state in Playwright or an explicit wait in Selenium. A fixed delay is less reliable because page load time varies.
- Wait for page-specific content: if the element appears after client-side rendering, wait for that element or a known readiness condition instead of assuming navigation completion means it is ready.
- Set the viewport: responsive layouts can move or resize the target. Use a deliberate viewport for repeatable results.
- Check overlays: consent dialogs, popups, or sticky UI can cover content or change the page layout. Dismiss or handle them according to your capture requirements.
- Consider lazy content: images or sections may load only when scrolled into view. Scroll to the target or use the full-page behavior appropriate to the framework, then verify the rendered result.
- Use a deliberate output format: choose PNG when preserving sharp edges and text matters; consider JPEG when a smaller photographic image is acceptable. Match the file extension to the format selected.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Strict mode or multiple-match error | The locator matches more than one element. | Check the count, scope to a meaningful parent, or add a distinguishing accessible name or attribute. Avoid positional selection unless order is intentional. |
| Timeout waiting for the element | The selector is wrong, the page is still rendering, navigation failed, or the element is inside a frame. | Inspect the live DOM and selector. Wait for the right readiness condition, check navigation errors, and locate the correct frame if applicable. |
| Element screenshot is blank or incomplete | The target has not rendered, its content is lazy-loaded, or the page changed during capture. | Wait for visibility and page-specific readiness; scroll the target into view and verify its content before capture. |
| Wrong element captured | The locator uses repeated text, a broad selector, or an assumed position. | Use a role and name, unique ID, test ID, or meaningful attribute. Narrow by a stable parent region and verify uniqueness. |
| Screenshot is clipped or laid out differently | The viewport or responsive breakpoint differs from the expected layout. | Set the viewport explicitly and use an element screenshot for a single target or a full-page screenshot for the whole document. |
| Content is hidden behind a dialog or overlay | A consent banner, modal, popup, or sticky widget affects the rendered page. | Handle or dismiss the UI if permitted, or capture a different region. Confirm that the selected element is visible before saving. |
| Selenium cannot find an element immediately | The script searches before the page has rendered the target. | Use an explicit wait for the element’s visibility rather than relying on an immediate lookup or a fixed sleep. |
| XPath is hard to maintain | The expression depends on long paths through incidental markup. | Replace it with a unique ID, accessible locator, or compact CSS selector based on meaningful attributes when possible. |
8. Performance, reliability, and cost
For browser automation, navigation, page rendering, and waiting for content are usually the work to manage. Keep each run focused: launch a browser once for a batch of captures where appropriate, reuse a page or context when isolation requirements allow it, and close resources in a finally block. Choose a specific readiness condition rather than waiting longer than the page requires.
For reliable results, make the locator unique, set the viewport, wait for the actual target, and handle transient failures with bounded retries only when repeating the operation is safe. A retry cannot fix a selector that targets the wrong element. Save useful diagnostics, such as the URL, locator, match count, and failure reason, so you can distinguish page changes from timing issues.
Browser automation has infrastructure and maintenance costs: browser processes consume resources, and selectors can need updates when a site changes. A screenshot API can remove browser setup from your application, but it does not eliminate the need to specify the right URL and capture options. Check the provider’s documented behavior and billing rules before using it in a cost-sensitive workflow.
Or skip the browser setup
For a whole-page screenshot through the ScreenshotNeo website screenshot API, make one GET request. This request captures the page; it does not target a CSS selector for an individual element. See the ScreenshotNeo API documentation for request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
ScreenshotNeo removes known cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
FAQ
Does a locator screenshot include the whole page?
No. It captures the located element. Use a page screenshot’s full-page option to capture the scrollable document.
Should I use CSS selectors or XPath?
Use the clearest stable locator available. Prefer accessible or semantic locators in Playwright; in Selenium, prefer a unique predictable ID, then a focused CSS selector. Keep XPath focused when you use it.
Does CSS :target select an element for a screenshot?
No. It matches the element identified by the URL fragment. Browser automation locators are a separate mechanism.
Can I capture an element with ScreenshotNeo’s one-call request?
The example above captures a page from its URL. Use browser automation such as Playwright or Selenium when your task requires locating and screenshotting one DOM element.


