Troubleshooting wait_for CSS Selectors
The wait_for
parameter in ZenRows tells the scraper to pause until a specific CSS selector is found in the rendered HTML. This feature requires js_render
to be set to true
.
If ZenRows cannot find a matching element for the CSS selector, it will retry several times internally. If it still doesn’t match, the request will return a 422 error. This means your selector likely does not exist in the final HTML, or is too fragile to be reliable.
This guide helps you debug wait_for
failures and avoid common pitfalls.
Understanding wait_for
The wait_for
parameter targets dynamic content that loads asynchronously. This includes content that appears after an AJAX call (a background request that updates part of a page without reloading) or JavaScript rendering. Here’s a typical usage:
Common Resons for the 422 error when using wait_for
Selector Not Present in Final HTML
Inspect the site using browser DevTools
- Open the page
- Right-click the target content and choose “Inspect”
- Check if your selector exists after the page fully loads
Verify your selector
- Run
document.querySelectorAll('your_selector')
in the browser console - If it returns no elements, your selector is incorrect
Tips
- Use simple selectors like
.class
or#id
- Prefer stable attributes like
[data-testid="item"]
- Avoid overly specific or deep descendant selectors
Dynamic or Fragile Selectors
Some websites use auto-generated class names that change frequently. These are considered dynamic and unreliable.
- Re-check the page in DevTools if a previously working selector fails.
- Look for stable attributes like
data-*
. - Use attribute-based selectors, which are more stable.
Instead of this:
Use stable alternatives:
You can also combine multiple fallback selectors:
Content Is Conditional or Missing
When scraping at scale, it’s common to encounter pages where the expected content is missing or appears under certain conditions.
Common Scenarios Where Selectors Might Fail
-
Out-of-stock products: The product is valid, but some elements like the price or “Add to cart” button are missing.
-
Deleted or unavailable pages: You may be accessing product URLs directly, but the product has been removed. The site might return a 404 error or a custom error page without clearly changing the URL.
-
Failed pages: The page might fail to load properly causing your selector to not match any on the HTML.
-
Conditional rendering: Some content is only rendered based on user location, browser behavior, or scrolling. Especially on JavaScript-heavy websites.
How to Handle It
Use the following ZenRows parameters to help identify these cases:
-
original_status=true
Returns the original HTTP status from the target site. Helps distinguish between a bad selector and a broken page.PythonFor more details check the Original Status Documentation -
allowed_status_codes=404,500
Lets you capture and analyze error pages instead of discarding them.PythonFor more details check the Allowed Status Codes Documentation -
Best practices:
- Anticipate that some selectors may not match if content is missing or the page structure changes.
- Consider checking for fallback selectors or error indicators (like a 404 message or error class).
- Monitor your scraping jobs for unexpected increases in 422 errors, which may indicate site changes, missing data, or blocking.
The CSS Selector Exists but Still Fails
Sometimes, your CSS selector is correct but still triggers a 422 error. Here are possible causes:
- CSS selector is present but hidden (
display: none
)
ZenRows considers it valid. If you need a visible element, try a child or a wrapper that only appears when content is shown.You can find more information about advanced CSS selectors here. - CSS selector appears after user interaction
Use thejs_instructions
to simulate a click or scroll action first. - The page relies on external scripts (slow loading)
Try a differentwait_for
selector that appears earlier in the loading process. Alternatively, switch to our Scraping Browser, which offers longer session times and allows you to manipulate requests more deeply through Puppeteer or Playwright. - CSS selector Typos:
Double-check for spelling errors, missing dots (.) for classes, or missing hashes (#) for IDs.
Alternative: Manual Wait
Instead of waiting for a selector, you can add a fixed delay using the wait
parameter:
Useful when dynamic elements take time to appear but don’t have consistent selectors. The maximum wait time is 30 seconds.
Real-World Case Example
Let’s say you’re targeting the product grid on scrapingcourse.com/ecommerce/
, and your request fails with a 422 error while your wait_for
CSS selector is:
This selector is syntactically valid, but it does not match any element in the HTML of the target page, so ZenRows cannot proceed and returns a 422 error.
Inspecting the product section reveals the correct selectors:
Valid alternatives:
CSS Selector Cheat Sheet
Selector | Example | Use Case |
---|---|---|
.class | .price | Wait for an elements with class “price” |
#id | #main-content | Wait for an element with ID “main-content” |
[data-attr] | [data-loaded="true"] | Wait for attribute presence |
[attr^="val"] | [id^="item-"] | Attribute starts with “item-” |
[attr$="val"] | [src$=".png"] | Attribute ends with “.png” |
A > B | .list > .item | Direct child of a parent |
A B | .list .item | Any descendant item inside a parent |
A, B | .price, .discount | Match either .price or .discount |
:nth-child(n) | li:nth-child(2) | Select the 2nd child (or any Nth) of its parent |
:first-child | div:first-child | First child of a parent element |
:last-child | div:last-child | Last child of a parent element |