Skip to main content

Recipes guide

Capture interactions with recipes

Recipes tell each capture what to click, open and expand so reviewers see every state of your site — not just what loads first.

What a recipe is

A recipe is a short script, written in YAML or JSON, that runs inside the capture browser. It can sign in to a members area, open accordions and tabs, step through carousels, hover menus open and record extra labelled pages in the PDF for each state a reviewer needs to see.

Every recipe is validated against a JSON Schema before it can be saved or used, so mistakes such as a misspelled step or a missing parameter are caught in the editor rather than halfway through a capture. Recipes are available to customer organisations.

A complete example

This recipe signs in to an HCP site, captures the dosing page with every section open and with a second tab selected, and on every page expands the ISI tray, records each hero carousel slide, opens the products menu and captures four frames of a hero animation.

version: 1
name: Brand X HCP site
match:
  - "https://hcp.brandx.com/**"
viewports: [desktop-1440, phone-6.5]
login:
  url: https://hcp.brandx.com/login
  steps:
    - fill: { selector: "#email", value: "{{secret.username}}" }
    - fill: { selector: "#password", value: "{{secret.password}}" }
    - click: { selector: "button[type=submit]" }
    - wait: { for: url, pattern: "**/dashboard" }
pages:
  - match: "**/dosing"
    steps:
      - expand-all-accordions: {}
      - capture: { label: "Dosing - all sections expanded" }
      - click: { selector: "[data-tab='pediatric']" }
      - wait: { ms: 500 }
      - capture: { label: "Dosing - pediatric tab" }
  - match: "**"
    steps:
      - expand-isi-tray: {}
      - advance-carousel: { selector: ".hero-carousel", capture_label: "Hero slide {n}" }
      - hover: { selector: "nav .products" }
      - capture: { label: "Products menu open" }
      - capture-frames: { selector: ".hero-animation", count: 4, interval_ms: 500, label: "Hero animation frame {n} of {count}" }

The same structure works in JSON:

{
  "version": 1,
  "name": "Brand X public site",
  "match": ["https://www.brandx.com/**"],
  "pages": [
    {
      "match": "**/faq",
      "steps": [
        { "expand-all-accordions": { "selector": ".faq details" } },
        { "capture": { "label": "FAQ - all answers open" } }
      ]
    }
  ]
}

Recipe structure

Top-level recipe keys
KeyRequiredDescription
versionYesSchema version. Always 1 for now.
nameYesA name your team will recognise in the recipe library and on job records.
matchYesOne or more URL globs. The recipe applies to jobs whose start URL matches any of them.
viewportsNoDevice views to capture, e.g. desktop-1440, phone-6.5, tablet-10.5. If omitted, the views chosen when starting the job are used.
loginNoA login url and the steps that sign in, run once before the crawl starts.
pagesNoA list of page blocks, each with a match glob and the steps to run on matching pages.

Steps in a block run in order. Each step is a single key — the step type — whose value holds its parameters. Use {} for a step with no parameters.

Matching pages

Both the recipe-level match and each page block's match are globs:

  • ** matches any path, across any number of segments — "**" on its own matches every page.
  • * matches exactly one path segment — "**/products/*" matches /products/alpha but not /products/alpha/dosing.
  • A page-block glob such as "**/dosing" matches the dosing page wherever it sits in the site.

The first matching page block wins. Put specific blocks first and a catch-all "**" block last. In the example above, the dosing page runs only its own steps; if you also want the ISI tray expanded there, add expand-isi-tray to the dosing block as well.

Login and secrets

The optional login block opens its url and runs its steps once, before the crawl begins. The session is then reused for every page and device view in the job. End the login with a wait so the capture knows sign-in succeeded.

Never put a password in a recipe. Use {{secret.name}} placeholders instead — for example {{secret.username}} and {{secret.password}}. When you start a job you are asked for a value for each secret the recipe uses. Values are encrypted on receipt, used only inside the capture worker, never stored in the recipe and deleted when the job ends.

Staging sites protected by HTTP Basic or NTLM authentication don't need login steps — enter those credentials in the job's site access settings instead.

Step reference

Optional parameters are marked. Selectors are standard CSS selectors.

click

Clicks an element, such as a tab, button or 'Read more' link.

  • selector — CSS selector of the element to click.
- click: { selector: "[data-tab='pediatric']" }

hover

Moves the pointer over an element to reveal menus, tooltips or hover states.

  • selector — CSS selector of the element to hover.
- hover: { selector: "nav .products" }

fill

Types a value into a text field. Use secrets for credentials.

  • selector — CSS selector of the input.
  • value — Text to enter; may contain {{secret.name}} placeholders.
- fill: { selector: "#email", value: "{{secret.username}}" }

select

Chooses an option in a drop-down list, by option value or by visible label.

  • selector — CSS selector of the <select>.
  • value | label — Either the option's value or its visible label.
- select: { selector: "#specialty", label: "Dermatology" }

check

Ticks or clears a checkbox or radio button, such as an 'I am a healthcare professional' gate.

  • selector — CSS selector of the checkbox or radio.
  • checked — true to tick, false to clear.
- check: { selector: "#hcp-confirm", checked: true }

submit

Submits a form.

  • selector — CSS selector of the form, or of an element inside it.
- submit: { selector: "form#hcp-gate" }

press

Presses a keyboard key, optionally with focus on a specific element.

  • key — Key name, e.g. Enter, Escape, ArrowRight.
  • selectoroptional — Element to focus first.
- press: { key: "Escape" }

wait

Pauses until a condition is met. Use exactly one form.

  • ms — Wait a fixed number of milliseconds.
  • selector (+ state) — Wait for an element; state is visible (default) or hidden.
  • for: url + pattern — Wait until the page URL matches a glob, e.g. after login.
  • for: network-idle — Wait until network activity has settled.
- wait: { selector: ".results", state: visible }
- wait: { for: url, pattern: "**/dashboard" }
- wait: { for: network-idle }
- wait: { ms: 500 }

scroll-to

Scrolls an element into view, for example to trigger lazy-loaded content.

  • selector — CSS selector of the element.
- scroll-to: { selector: "#clinical-data" }

expand-all-accordions

Opens every accordion or disclosure on the page so all hidden text is captured.

  • selectoroptional — Limit to accordions inside this container. Without it, common accordion patterns — such as <details> elements and ARIA disclosures — are opened across the page.
- expand-all-accordions: {}
- expand-all-accordions: { selector: ".faq" }

expand-isi-tray

Expands the sticky Important Safety Information tray. Common trays are detected automatically; use this step for custom implementations.

  • selectoroptional — CSS selector of the tray or its expand control.
- expand-isi-tray: { selector: "#isi-tray .expand" }

dismiss

Closes an overlay that hides content, such as a pop-up or interstitial.

  • selector — CSS selector of the close or dismiss control.
- dismiss: { selector: ".modal .close" }

capture

Captures the current state of the page as an extra, labelled PDF page.

  • label — Label shown in the PDF bookmarks and on the page.
  • full_pageoptional — Capture the full length of the page (default true).
- capture: { label: "Products menu open" }

capture-frames

Captures several frames of an animation at a fixed interval, each as a labelled page.

  • selectoroptional — Element to focus on; the whole page if omitted.
  • count — Number of frames to capture.
  • interval_ms — Time between frames in milliseconds.
  • label — Label for each frame; {n} and {count} are replaced.
- capture-frames: { selector: ".hero-animation", count: 4, interval_ms: 500, label: "Hero animation frame {n} of {count}" }

How animations are handled

You don't need a recipe for most motion. On every page, before capture:

  • CSS and JavaScript animations and transitions are advanced to their end state, so fading or sliding text is fully visible.
  • Lazy-loaded content is brought into view so it appears in the PDF.
  • Carousels, videos and animations are detected and listed in the motion content report, so reviewers know what a static PDF cannot show in full.

Use advance-carousel when every slide must be reviewed, and capture-frames when the sequence of an animation matters — for example a claim that builds over several frames.

The editor and test runs

In the app, the recipe editor validates as you type and points to the line and field of any error. Use Test run to run the recipe on a single page and see each labelled capture before you start a full job. Each job records a snapshot of the recipe it used, so the PDF can always be traced back to the exact steps that produced it.

AI auto-recipe

For customer organisations that enable AI features, auto-recipe examines a page and proposes a recipe — accordions to open, tabs to click, carousels to advance and the ISI tray to expand. The proposal opens in the editor for your team to review, edit and test; nothing runs until a person saves it. Like all AI features it is assistive, not an MLR decision.

Tips for reliable recipes

  • Prefer stable selectors. IDs and data attributes such as [data-tab='pediatric'] survive redesigns; long chains like div > div:nth-child(3) > span do not.
  • Ask developers for test hooks. A few data- attributes on tabs, accordions and the ISI tray make recipes simple and durable.
  • Wait for conditions, not time. wait: { selector: ... } or for: network-idle is faster and more reliable than long fixed waits; keep ms waits short.
  • Label captures for reviewers. Labels appear in the PDF bookmarks — describe the state, e.g. "Dosing - pediatric tab".
  • Order page blocks from specific to general. The first matching block wins.
  • Test on one page first. Use Test run before starting a full-site job.

Questions about a tricky site? Contact us or request a demo.