# Extralt Documentation > Managed ecommerce extraction and product data enrichment for recurring multi-store workflows. Extralt builds and runs managed extraction for supported public ecommerce websites, then turns Captures into normalized product data and a connected cross-store analytical model. Explore provides coverage, relationship, current-market, change, Variant, Offer, and history views; four price, availability, and assortment Analyses; custom Query across the connected model; and matching dashboard Agent tools. Saved or scheduled Analyses, alerts, dedicated Analysis file exports, and shared agent-facing discovery are not current capabilities. Current product overview: https://extralt.com/products Current use cases: https://extralt.com/use-cases Pricing: https://extralt.com/pricing Concise AI index: https://extralt.com/llms.txt --- --- ## How Extralt Works Extralt's "third way" architecture -- AI-generated crawlers compiled to Rust for speed and adaptability. URL: https://extralt.com/docs/concepts/how-extralt-works Two approaches dominate web data extraction today, and both have serious tradeoffs. **Traditional scrapers** use hand-coded selectors (CSS, XPath) that break when a website changes its HTML structure. Maintenance is constant and scaling across many sites is expensive. **AI-at-runtime scrapers** send each page to a language model for extraction. This is flexible but slow and expensive -- you're paying for LLM inference on every single page. ## The third way Extralt combines the best of both approaches: 1. **AI generates the crawler at build time.** When you request a robot for a new site, Extralt's AI analyzes the target site, understands its structure, and generates extraction logic. 2. **The crawler compiles to Rust.** The generated logic is compiled into a high-performance Rust binary (a dynlib). No LLM inference at extraction time. 3. **Extraction runs without per-page LLM inference.** The compiled Robot fetches pages and applies the generated extraction logic repeatedly. This separates generative build work from repeated extraction. Website coverage still depends on whether the harness can generate and validate reliable logic for the requested site and market. ## Build vs. run | Phase | What happens | Speed | Cost | | --------- | ----------------------------------------------------------------------------------------- | ---------------- | -------------------------------- | | **Build** | The harness analyzes a source, generates and validates extraction logic, then compiles it | Varies by source | Build work | | **Run** | Compiled robot crawls and extracts data | Fast | 2 credits per successful Capture | Build-time generation is separated from repeated extraction, so running the Robot does not require an LLM call for every page. ## Consistent output All robots extract data into the same base ecommerce schema. Whether you're scraping a luxury fashion site or a hardware store, the output has the same structure: title, brand, SKUs, offers, pricing, identifiers. This consistency means you can: * Read Capture fields through one base extraction contract * Build pipelines that work regardless of source * Switch between robots without changing your code ## Robot reuse For a compatible host and country that has already been validated, Extralt can return the existing Robot. Otherwise, the Robot tracks its internal build until it is completed or failed. Site changes can require new generation and validation work; reuse is determined by compatible website coverage, not by a generic scraper template. --- ## Security & Privacy How Extralt protects customer data with organization isolation, API and MCP authentication, Stripe billing, public-web extraction boundaries, and GDPR controls. URL: https://extralt.com/docs/concepts/security-privacy Extralt is designed with data isolation and security as core principles. Every layer of the platform — from authentication to storage to billing — enforces strict org-scoped boundaries so your data stays private. ## Organization isolation Customer operations and data are scoped to an organization. This includes Robots, Runs, Captures, Enrichments, Items, materialized entities, credits, API keys, and MCP connections. * API keys only access data within their organization * MCP connections only access the organization selected during OAuth consent * Users in one org cannot see another org's data * Even if you have multiple orgs, each is a separate, isolated environment ## API and MCP authentication The public REST API accepts organization-scoped API keys. MCP accepts OAuth access tokens and resolves the selected organization on every request. API keys are not accepted by MCP, and OAuth access tokens are not accepted by the REST API. ## API keys * Keys are generated per organization from the dashboard * Each key is scoped to one organization * Keys can be revoked at any time * Compromised keys should be revoked and replaced immediately **Best practices:** * Store keys in environment variables, not in code * Never commit keys to version control * Use separate keys for development and production * Rotate keys periodically ## MCP connections MCP authorization happens in the browser. Sign in, select the organization the client should use, and approve the requested access. Extralt never accepts an organization ID from a tool call as proof of access. ## Billing security Billing is handled entirely by Stripe, a third-party payment processor. Extralt never stores, processes, or has access to your credit card information or payment details. When you subscribe or manage your billing, you're redirected to Stripe's secure interface. ## Data handling * Extracted and processed records retain organization ownership throughout the pipeline * Dashboard, public API, and MCP requests apply the authenticated organization context * Exports and dashboard AI queries only return data in the authenticated organization * Extralt extracts supported public ecommerce pages; authentication does not grant the crawler access to private source data See [Access Surfaces](/docs/data/access-surfaces) for the exact capabilities of the dashboard, public API, MCP, exports, dashboard AI queries, and dashboard agent. ## Questions If you have security questions or need to report a vulnerability, contact us at [support@extralt.com](mailto\:support@extralt.com). --- ## The Extralt pipeline Understand how Extract, Enrich, and Explore turn ecommerce pages into structured, matched product data. URL: https://extralt.com/docs/concepts/the-4-es Extralt's product pipeline has three stages. Each stage has a distinct output and can be used without pretending the next stage is already complete. ## Extract **Collect product data from ecommerce pages.** Extract runs compiled logic built and validated for a website against supported public product and catalog pages. It returns Captures with the original URLs, observation times, product content, options, SKUs, commerce data, ratings, media, and page-level price and availability summaries. Extract is useful independently when the job is to collect recurring, structured product data without maintaining a custom scraper for every website. ## Enrich **Normalize, classify, and publish the analytical model.** Raw extraction gives you data in the source language with varying formats. Enrich: * Translates product data to English * Classifies products using an industry-standard taxonomy * Extracts normalized product signals supported by page evidence * Maps options and SKU data into one page-grain Item * Connects exact Products and Variants to Listings, Offers, Reviews, and Stores * Publishes the complete committed scope before the Enrichment becomes ready Use the [Product Taxonomy Explorer](/tools/taxonomy-explorer) to inspect the category and attribute model Enrich maps products into. Enrich's paid unit is one successfully normalized Item per Capture. Publishing the connected analytical model is included and consumes no additional credits. Matching quality depends on available identifiers and product evidence. ## Explore **Search, compare, and analyze.** Explore currently provides: * dataset overview and filter facets; * current market rows grouped by exact Variant, country, and currency; * relationship and change evidence; * Variant detail with current Offers and observed history; * Price position, Price movements, Availability changes, and Assortment overlap as Analyses; * custom Query across Products, Variants, Listings, Offers, Reviews, and Stores; * the same Analyses and Query surface through the dashboard Agent. ## The core principle > Extract costs 2 credits per successful Capture, and Enrich costs 1 credit per Capture. Publishing the connected model and reading the customer dataset through the available surfaces are included. The dashboard Agent and supported AI-assisted dashboard queries are included with an active subscription and do not consume credits. Work approved through the Agent uses the normal Extract and Enrich credit units. --- ## Access surfaces See which Extralt operations and data are available in the dashboard, public API, MCP, file exports, Query, and dashboard Agent. URL: https://extralt.com/docs/data/access-surfaces Extralt exposes the same customer dataset through several deliberately different surfaces. Availability in one surface does not imply that every other surface has the same operation or result shape. ## Coverage matrix | Capability or data | Dashboard | Public API | MCP | File export | Query | Dashboard Agent | | ------------------------------------ | ----------------------------------- | -------------------------------------------------------------------------------- | --------------------------------- | -------------------------------------------- | ------------------------------------------- | ------------------------------------------------ | | Robots | Create, inspect, use, delete | Create, list, read, delete | Prepare, list, inspect, delete | No | No | Read; can prepare a Robot build for approval | | Runs | Create, inspect, restart, stop | List, create, read, restart, stop | List, start, inspect, retry, stop | No | No | Read; can prepare an approved Run | | Schedules | Create, edit, pause, resume, delete | Full lifecycle | Full lifecycle | No | No | Read; can prepare an approved Schedule | | Imports | Create and inspect | Create and read status | Start and inspect status | Resulting Captures can be exported by Import | Captures can be scoped to one Import | Read-only | | Captures | Browse and inspect | List and count | List, count, export | JSONL or Parquet by Run or Import | Yes, optionally scoped to one Run or Import | Yes, with a persisted Query result | | Enrichments | Create, inspect, stop | List, create, read, stop | List, start, inspect, stop | No | No | Read; can prepare an approved Enrichment | | Items | Browse and inspect | List and detail | List and inspect | JSONL or Parquet in the dashboard | Yes, optionally scoped to one Enrichment | Yes, with a persisted Query result | | Relationships | Browse the connected model | No dedicated v1 relationship route | No dedicated tool | No | Yes, across the connected Explore model | Yes, through custom Query | | Changes | Browse the dedicated Explore view | No dedicated v1 Changes route | No dedicated tool | No | No standalone custom Query surface | No dedicated Changes tool | | Current markets and Variant evidence | Browse and drill down | Overview, facets, current markets, Variant metadata, current Offers, and history | Same supported evidence | No dedicated file export | Yes through the connected Explore model | Yes through custom Query | | Four packaged Analyses | Dedicated pages | Four pageable routes | All four Analyses | No dedicated file export | Separate from custom Query | Runs the same contracts and links to their pages | The generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) is authoritative for public routes, filters, request fields, response schemas, and page limits. MCP publishes its own tool schemas and is documented in [Connect through MCP](/docs/guides/using-mcp). Dashboard-only and Agent-only operations are not public API contracts. ## Public API The public API exposes stable v1 Extract, Enrich, and Explore resources. Explore provides overview and facets, current market evidence, separate Variant metadata, current-Offer and history resources, and all four packaged Analyses. There is no general public SQL endpoint or public materialization mutation. Final analytical entities are published as part of the Enrichment lifecycle and read through the supported Explore routes. ## MCP MCP exposes the customer-facing API capabilities as task-oriented tools for compatible agents. It uses browser OAuth and the organization selected during consent rather than an API key or an organization field in tool inputs. See [Connect through MCP](/docs/guides/using-mcp) for setup and access rules. ## Dashboard Query Dashboard Query supports three product targets: * Captures from all data, one Run, or one Import; * Items from all data or one Enrichment; * Explore across Products, Variants, Listings, Offers, Reviews, and Stores. For Explore, the customer asks one question without choosing a table. Extralt loads the connected data model, including allowed entities, fields, relationships, and canonical current-state definitions, then generates a bounded read query. The persisted artifact keeps the question, SQL, result, status, and truncation state. Query returns at most 100 rows and is not pageable. It is a first-party dashboard surface, not a public v1 endpoint or direct ClickHouse connection. ClickHouse's reader role enforces read-only access, organization row policies, and resource ceilings; the API adds query-size, time, row, and response-size budgets. ## Dashboard Agent The Agent can inspect the operational resources already represented in the dashboard, run the four packaged Analyses, and use the same persisted Query surface for Captures, Items, and the connected Explore model. It can also prepare Robot, Run, Schedule, and Enrichment operations. Those operations execute only after explicit dashboard approval. Imports remain read-only through the Agent. ## Subscription access Writes require an active subscription. The 30-day post-subscription grace period is read-only and includes available exports. Grace also permits stopping active work, pausing schedules, and replaying a completed idempotent API request; those exceptions cannot create new work or consume credits. Customer data access is blocked after grace until the organization is reactivated. --- ## Data model Understand the grain, lineage, relationships, and current-state boundaries of Captures, Items, Products, Variants, Listings, Offers, and Stores. URL: https://extralt.com/docs/data Extralt separates source observations from normalized records and cross-store entities. That separation keeps a page that was actually observed distinct from a Product or Variant inferred across several sources. ## Lineage Data follows the same Extract and Enrich stages shown in the dashboard. Operational records coordinate each stage; the resulting Captures, Items, relationships, and observations belong to the organization's analytical dataset. Explore reads that dataset. ## Entity grains | Entity | One record represents | Primary lineage or relationship | | ------- | ----------------------------------------------- | -------------------------------------------------- | | Capture | One successfully extracted or imported page | Run or Import, source URL, observation time | | Item | One successfully enriched Capture | `capture_id`, `enrichment_id` | | Product | One normalized product family | Parent of one or more Variants | | Variant | One exact canonical configuration | Product and equivalent Listings | | Listing | One source SKU identity in one Store and market | Variant, Store, source URL | | Offer | One seller, price, and availability observation | Listing, Capture, Run, observation time | | Review | One normalized review aggregate observation | Listing, Store, Run, observation time | | Store | One host and country pair | Referenced by Items, Listings, Offers, and Reviews | | Change | One observed change to one entity aspect | Entity, Run, observation time | ## Observations and current entities Captures and Items are page-grain observations with source URL and time lineage. Offers and Changes are also observations: they record a fact at a point in time. Products, Variants, Listings, and Stores represent current dimensions. Reviews are append-only observations; current Review views select the latest known aggregate for each active Listing. The API and Explore views own that current-state contract; callers do not need to reason about ClickHouse merge behavior or storage engines. ## Operational and analytical names A **Robot**, **Run**, or **Enrichment** belongs to the control plane and configures or tracks processing work. A **Capture**, **Item**, **Product**, **Variant**, **Listing**, **Offer**, **Review**, **Store**, or **Change** belongs to the analytical customer dataset. A Robot contains extraction logic for a host and country. A Store currently represents a host and country in one organization's analytical dataset. They may describe the same website and market, but they do not share an identity or lifecycle. Creating or using a Robot does not create a globally shared retailer entity. ## Scope boundaries The dataset contains observed public product evidence. It does not contain sales, transactions, revenue, turnover, traffic, market share, demand, margin, or promotion codes that were not visible in the extracted data. Coverage is conditional on the stores, countries, URLs, and observation times the organization selected. “Current” means the latest observation in that dataset, not a continuously synchronized view of the whole market. Continue with the [access-surface matrix](/docs/data/access-surfaces), the [semantic model](/docs/data/semantic-catalog), and [query semantics](/docs/data/query-semantics). --- ## Query semantics Interpret grain, current state, time, price, availability, assortment, reviews, coverage, and freshness consistently across Explore. URL: https://extralt.com/docs/data/query-semantics Correct ecommerce analysis depends on what one record represents, how entities relate, and when the evidence was observed. These definitions apply to Explore evidence views, packaged Analyses, Explore AI, and Agent answers. ## Choose the strongest contract | Question | Preferred surface | | ----------------------------------------------------------------------------------------- | ------------------------------------------- | | Stable competitive price, price-movement, availability-change, or exact-assortment metric | Packaged Analysis | | One-off grouping, count, exception list, or joined evidence question | Explore AI | | Exact current market or Variant evidence | Purpose-built Explore view or public API | | Raw extracted or normalized page data | Capture or Item view, API, export, or Query | Packaged Analyses own their formulas, eligibility, denominators, and evidence. Explore AI may inspect the same data but must not silently reinterpret those contracts. ## Organization scope and grain The authenticated organization determines the customer dataset. Identifiers only have meaning inside that dataset unless a response explicitly says otherwise. The connected Explore path is: ```text Product -> Variant -> Listing -> Offer observations |-> Review observations Store -------------------+ ``` A Product family can have several exact Variants. One Variant can resolve to several Store Listings. One Listing can have many Offer and Review observations over time. Joining several one-to-many paths can multiply rows, so counts and aggregates must first return to the grain named in the question. ## Active Listings An active Listing is the latest known Listing state without explicit removal evidence. A Listing does not become inactive merely because a later Offer is missing. Removed Listings remain available when a history or removal question explicitly asks for them. ## Current Offers Offers are append-only observations. The current Offer set is **every Offer from each active Listing's latest observed Extract run**. Latest-run selection happens before filtering by country, currency, condition, seller, price, or availability. Selecting the latest row independently for each seller or currency can incorrectly retain Offers that disappeared from a later Listing observation. At the natural current-Offer grain, one row represents a Listing, seller, condition, and currency. Store-level price or availability metrics deliberately reduce marketplace sellers so a Store with many sellers does not receive extra weight. ## Current Reviews Reviews are append-only aggregate observations, not one mutable row. Current Reviews select the latest known aggregate for each active Listing. Each observation contains a review count and a score normalized to `0-100`. Review counts and scores are evidence attached to a Listing. They do not provide review text, sentiment, unique reviewers, sales, or reliable additive counts across syndicated Products or sibling Variants. ## Observed assortment, newness, and removal Observed assortment is the set of distinct exact Variants connected to active Listings in the selected Store and country scope. Multiple Listings and sellers must not multiply one Variant. "New" means first observed in this organization's Extralt dataset: * Variant newness uses its first-known time; * Listing newness uses its first-seen time; * Product-level launch time is not available and must not be invented. "Removed" requires explicit Listing removal evidence. A missing seller or Offer is no longer observed, not automatically removed or out of stock. ## Time meanings | Time | Meaning | | ------------------------- | ------------------------------------------------- | | Observation or Run start | When Extralt observed the source page | | Published time | A date reported by the source when available | | First seen or first known | First valid evidence in this organization dataset | | Last seen | Most recent valid Listing evidence | | Removed time | Explicit Listing removal evidence | | Change observation | When a semantic before/after change was recorded | Stores are often observed at different times. Describe the actual evidence range rather than presenting asynchronous observations as one synchronized market snapshot. ## Country, currency, and condition Store and Listing context is country-specific. Partition market comparisons by country unless the question explicitly requires several markets. Never compare or aggregate price amounts across currencies without an explicit conversion source and timestamp. Extralt does not currently provide currency conversion. Include currency in every price result and keep Offer condition explicit when it affects comparability. ## Availability and stock Availability is an observed state derived from current Offers. At Listing, seller, and condition grain: 1. the state is available when any qualifying current row is available; 2. otherwise it is unavailable when any row explicitly reports out of stock; 3. otherwise it is unknown. Currency is not part of availability grain unless the question explicitly asks for currency-specific availability. At Store and Variant grain, a Store is available when any qualifying current Offer is available. Keep absent, unknown, explicitly unavailable, and removed distinct. Categorical stock does not reveal units on hand, future inventory, demand, lost sales, or continuous outage duration. ## Missing values An empty value or schema default is not necessarily a measured zero. A website may not expose a field at all. Use the source URL, observation time, result coverage, and relevant exclusions before interpreting absence as zero, false, or unavailable. ## Coverage and freshness A trustworthy result states the selected Stores and countries, currencies and conditions, evidence-time range, and included or excluded populations relevant to its denominator. When cross-store identity is required, matched and unmatched coverage must remain visible. For an Analysis, summary, coverage, and freshness describe the selected scope; the evidence rows can span several API pages. For Explore AI, the persisted rows are a bounded result and `truncated` means the result should be narrowed. ## Query execution boundary Explore AI loads a model of the relevant entities, fields, relationships, and definitions before generating SQL. The service returns at most 100 rows and stores the effective SQL with the result. It is a dashboard feature, not unrestricted public SQL access. ClickHouse's reader role and row policies enforce read-only, organization- scoped access and resource ceilings. The API adds transport, execution, row, and response-size limits. Query-level settings cannot raise the role ceilings. Continue with the [semantic model](/docs/data/semantic-catalog) for entity grains and [Exploring data](/docs/guides/exploring-data) for Analysis behavior. --- ## Semantic model Understand Extralt records and analytical entities, their grain, identity, lineage, relationships, and current-state behavior. URL: https://extralt.com/docs/data/semantic-catalog This page defines what Extralt data means. It intentionally does not duplicate physical ClickHouse schemas or public response types. Explore AI receives the current field catalog at runtime, while the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) owns exact public request and response schemas. ## Three connected layers | Layer | Purpose | Main records | | ---------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | Extract evidence | Preserve what was collected from a page or imported catalog, with URL and observation lineage | Capture | | Enrich output | Normalize one successful Capture into a durable page-grain record | Item | | Analytical model | Connect exact configurations, Store Listings, and observed commerce evidence across pages | Product, Variant, Listing, Offer, Review, Store, Change | Captures and Items remain useful independently. Explore normally reads the connected analytical model published before an Enrichment becomes terminal. ## Records and entity grains | Record or entity | One record represents | Use it for | | ---------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | **Capture** | One successfully extracted or imported page record | Original page content, source URL, observation time, extracted SKUs and Offers, export, and Enrich input | | **Item** | One successfully enriched Capture | Normalized English content, taxonomy, attributes, signals, options, embedded normalized SKU data, and Capture lineage | | **Product** | One current canonical product family in an organization dataset | Family-level title, brand, taxonomy, attributes, signals, option axes, and media | | **Variant** | One current exact product configuration under a Product | Cross-store identity for the same precise option or identifier combination | | **Listing** | One Store SKU identity in one country | Source URL, Store, exact source identity, Variant resolution, and first/last/removal evidence | | **Offer** | One seller, price, currency, condition, availability, and stock observation for a Listing | Current price and availability, marketplace evidence, and history | | **Review** | One review-count and normalized-score observation for a Listing | Current review evidence and observed aggregate history | | **Store** | One hostname and country pair in an organization dataset | Market context for Listings, Offers, and Reviews | | **Change** | One observed semantic change to one entity aspect | Before/after evidence for additions, changes, removals, and reappearances | An Item is not a canonical Product. It is the normalized evidence used to publish Products, Variants, Listings, Offers, Reviews, Stores, and Changes. ## Relationships ```text Capture -> Item Product -> Variant -> Listing -> Offer observations |-> Review observations Store -------------------+ ``` * A Product has one or more exact Variants. * A Variant can resolve equivalent Listings observed in several Stores. * A Listing belongs to one Store market and one current Variant resolution. * Offer and Review observations belong to a Listing and retain observation lineage. * Product, Variant, brand, and category context for an Offer or Review is reached through its Listing. These relationships are supported by Explore AI, but they are not a promise of unrestricted access to physical tables. See [Access surfaces](/docs/data/access-surfaces) for the supported interfaces. ## Observation records and current state Capture, Item, Offer, Review, and Change rows preserve observations. Product, Variant, Listing, and Store rows represent current dimensions in Explore. Purpose-built views and the Query model apply these current-state rules: * **active Listings** are latest Listing states without explicit removal; * **current Offers** are all Offers from each active Listing's latest observed Extract run, selected before Offer filters; * **current Reviews** are the latest known review aggregate for each active Listing; * **observed assortment** is the distinct set of Variants connected to active Listings in the selected Store and country; * **new** means first observed in this organization dataset; * **removed** requires explicit Listing removal evidence; * **availability** preserves available, unavailable, unknown, absent, and removed as different states. See [Query semantics](/docs/data/query-semantics) for the complete comparison and interpretation rules. ## Identity boundaries Product and Variant ids are Extralt canonical identities inside one organization's final dataset. Source product ids, handles, SKUs, GTINs, and MPNs are evidence used during normalization and matching; none is guaranteed to be a universal primary key. Matching quality depends on the identifiers and product evidence available in the collected pages. The model supports exact cross-store Variant comparison, not substitutes, aesthetic similarity, or exhaustive market identity. A Store is a storefront in one country. It is not a Robot, seller, legal company, retailer group, traffic estimate, or sales account. A Robot is operational extraction tooling and has a separate lifecycle. ## Data boundaries The model contains observed catalogs and product details, identifiers, options, prices, compare-at prices when exposed, availability, categorical stock, sellers, review aggregates, media, timestamps, and page URLs. It does not contain sales, transactions, revenue, turnover, traffic, demand, margin, market share, review text, sentiment, or unobserved promotion codes. Coverage is limited to the Stores, countries, URLs, and observation times the organization selected. For the available dashboard, API, export, Query, and Agent paths, continue with [Access surfaces](/docs/data/access-surfaces). --- ## Account Setup Create an Extralt account, set up your organization, choose a credit plan, and generate an org-scoped API key for dashboard and API workflows. URL: https://extralt.com/docs/guides/account-setup This guide walks you through creating an organization, choosing a plan, and generating your first API key. ## Create an account Go to [extralt.com](https://extralt.com) and sign up. You can use Google or GitHub. ## Create an organization After signing in, create an organization. Everything in Extralt is scoped to an organization: robots, runs, captures, credits, and API keys. You can create multiple organizations, each with its own subscription and data. Use the **org switcher** in the top-left of the dashboard to switch between them. ## Subscribe to a plan Navigate to the subscription page in the dashboard. You'll be redirected to Stripe to complete your subscription. | Plan | Price | Credits | Concurrent runs | | --------- | -------------- | ------- | --------------- | | **Start** | $29/mo | 10,000 | 1 | | **Scale** | $100-$1,000/mo | 100K-1M | Unlimited | The **Start plan** includes a 7-day free trial with 5,000 credits. No credit card required to start the trial. Billing is handled by Stripe. Extralt never sees your payment information. You can manage your subscription anytime from the dashboard, which redirects to Stripe. ## Generate an API key 1. Open the dashboard 2. Navigate to your API key settings 3. Create a new API key Your API key is scoped to the current organization. Keep it secret. If compromised, revoke it and create a new one. Use the key in API requests with the `Authorization` header: ``` Authorization: Bearer your-api-key ``` See [Authentication](/docs/using-the-api/authentication) for details. ## Manage your account * **Account settings** (top-right) — update profile, email, password * **Organization settings** (top-left org switcher) — rename org, manage members, switch orgs ## Next steps Once your account is ready, continue with the guides: * [Extracting data](/docs/guides/extracting-data) — create a Robot, start Runs, and monitor extraction * [Schedules](/docs/guides/schedules) — automate recurring Runs * [Working with Captures](/docs/guides/working-with-captures) — access and filter extracted data * [Credits & Billing](/docs/guides/credits-billing) — understand credit consumption and plan management --- ## Credits & Billing Understand how Extralt credits work, manage your subscription, and control ecommerce extraction and enrichment costs. URL: https://extralt.com/docs/guides/credits-billing Extralt uses a credit-based billing model. Credits are consumed by product-specific actions, and your subscription determines how many you get each month. ## How credits work * **Extract:** 2 credits per successful product-page Capture * **Enrich:** 1 credit per Capture * **Agent and supported AI-assisted dashboard queries:** included with an active subscription; no credits consumed * Extract credits are deducted as successful product-page Captures are produced, not when a run is created * Capture + Enrich costs 3 credits total * Unused credits do not roll over to the next billing cycle ## Subscription tiers | | **Start** | **Scale** | | ------------------- | ------------------ | -------------- | | **Price** | $29/mo | $100-$1,000/mo | | **Credits** | 10,000 | 100K-1M | | **Concurrent runs** | 1 | Unlimited | | **Agent** | Included | Included | | **Support** | Email | Priority | | **Free trial** | 7 days, 5K credits | -- | The Start plan includes a 7-day free trial with 5,000 credits. No credit card required. ## Checking your balance You can check your remaining credits in the dashboard or via the API. ## Managing your subscription Subscriptions are managed through Stripe. From the dashboard, navigate to your subscription settings to: * Upgrade or downgrade your plan * View billing history * Update payment method * Cancel your subscription Extralt never sees your payment information. All billing is handled securely by Stripe. ## Access after a subscription ends For 30 days after the last active subscription period ends, your organization has read-only dashboard and API access, including Capture exports. Creating or modifying resources, running AI features, and consuming credits require an active subscription. You can still stop active work and pause schedules during grace. A retry of a completed idempotent API request returns the original result, but cannot create new work. After 30 days, customer-data access is suspended, but you can still use the subscription area to reactivate. After 180 days, the organization is deactivated and can no longer be restored. Deactivation is a permanent access cutoff; it does not itself confirm physical deletion of Customer Data. ## Multiple organizations Each organization has its own subscription and credit balance. If you work with multiple organizations, each one needs its own plan. Use the org switcher in the top-left of the dashboard to switch between organizations. ## Setting budgets When creating a run, set a `budget` to limit the number of Captures produced. This helps control credit usage: ```json { "robot_id": "your-robot-id", "start_urls": ["https://example-store.com/products"], "budget": 50 } ``` Without a budget, a run will extract until the crawl is complete or there are not enough credits for the next successful product-page Capture. ## Result-based billing Extract is priced per successful product-page Capture. Category, search, collection, and other discovery pages do not consume credits. You do not pay separate line items for blocks, retries, JavaScript rendering, proxies, or crawler maintenance. Extralt handles the extraction infrastructure and only charges when it produces a Capture. ## Agent access The dashboard Agent is included with an active Start or Scale subscription, including the Start trial. Agent messages do not consume credits. When you approve an Agent plan, the resulting work uses the normal product pricing: Extract consumes credits for successful product-page Captures and Enrich consumes one credit per Capture. The Agent does not add another usage charge. Supported AI-assisted query surfaces in the dashboard are also included with an active Start or Scale subscription, including the Start trial, and do not consume credits. ## Schedules and credits Schedules create runs automatically on a cadence. Each successful product-page Capture produced during a scheduled run costs **2 credits**, just like manual runs. If your organization does not have enough credits for the next Capture, all active schedules automatically pause. They remain paused until you purchase additional credits or your next billing cycle adds credits. You can also manually pause and resume schedules at any time. See [Schedules](/docs/guides/schedules) for details. --- ## Enriching Captures Start an Enrichment, monitor its progress, and use the resulting product data. URL: https://extralt.com/docs/guides/enriching-captures Enrich turns Captures from one Extract Run into normalized product data you can compare across stores. It produces one Item per processed Capture and connects equivalent products, variants, listings, and offers for Explore. ## Before you start You need an Extract Run with Captures. Choose an Enrichment budget to set the maximum number of Captures to process. Enrich consumes one credit per Capture; cross-store matching and the resulting Explore data are included. Matching quality depends on the identifiers, options, and product evidence available in the source Captures. Enrich does not assume that every product can be matched across stores. ## Start an Enrichment **Dashboard:** open **Enrich > Enrichments**, create a new Enrichment, choose the source Run, and set the budget. You can also enable `auto_enrich` when creating an Extract Run. {/* SCREENSHOT_TODO: enrich-create-form | Show source Run selector, explicit budget, and submit action. Avoid customer data. */} **API:** ```bash curl -s -X POST "https://api.extralt.com/v1/enrich/enrichments" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: enrichment-create-example-1" \ -H "Content-Type: application/json" \ -d '{ "extract_run_id": "your-run-id", "budget": 100 }' | jq ``` Use the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) as the source of truth for the current request and response schema. ## Monitor and stop work The Enrichment list and detail views show the source Run, status, progress, errors, and budget. You can stop an active Enrichment from the dashboard or API. Stopping prevents additional Captures from being processed or charged. Results already produced remain available, and the Enrichment may stay active briefly before its status becomes `stopped`. {/* SCREENSHOT_TODO: enrich-detail | Show status, source Run, processed count, budget, and stop control in one frame. */} ## Use the results ## Inspect normalized Items Browse Items under **Enrich > Items**. The list can be scoped to an Enrichment; the detail view preserves Capture, Run, source URL, and observation lineage. {/* SCREENSHOT_TODO: item-detail-lineage | Show normalized title/taxonomy and the source Capture/URL lineage without exposing production customer data. */} The API supports paginated Item listing and Item detail. See the [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) for current filters and response fields. ## Compare products across stores When the Enrichment finishes, use Explore to inspect matched product and variant relationships, current offers, and observed changes across stores. Start with [Exploring data](/docs/guides/exploring-data) for the available dashboard and data-access paths. ## What Enrich produces An Item contains normalized product content, taxonomy ids and path, attributes, signals, image text, option axes, selected media, source SKUs and identifiers, review aggregates, country, Store key, source URL, and processing lineage. Explore uses the Products, Variants, Listings, Offers, Reviews, Stores, and Changes produced by the same Enrichment. See the [semantic catalog](/docs/data/semantic-catalog) for their field semantics. --- ## Exploring data Browse product evidence, run four ecommerce Analyses, ask custom questions, and inspect the observations behind every result. URL: https://extralt.com/docs/guides/exploring-data Explore turns the analytical model published by Enrich into current evidence, repeatable Analyses, and custom answers. It reads the organization's own Products, Variants, Listings, Offers, Reviews, Stores, and Changes. ## Choose the right Explore surface | Goal | Use | | --------------------------------------------------------------------------------------- | ------------------- | | Understand dataset coverage and available filters | Overview and facets | | Inspect relationships, changes, current markets, or one exact Variant | Evidence views | | Answer a recurring price, availability, or assortment question with a stable definition | Packaged Analysis | | Ask a one-off question across the connected product model | Explore AI | | Ask in conversation and continue to the relevant dashboard page | Dashboard Agent | Use a packaged Analysis whenever it fits the question. Its metric, eligibility, coverage, and evidence rules are explicitly defined. AI is the exploratory surface for other cuts of the data; it does not silently redefine an Analysis. ## Browse the evidence layer The Explore overview summarizes countries, taxonomy, brands, Stores, Variants, Listings, current Offers, availability, currencies, and the latest observation time. Facets return filter choices that actually exist in the organization's dataset. Facets are bounded suggestions rather than a pageable result. Current markets group qualifying Offers by exact Variant, country, and currency. They show price range, availability, Store and seller coverage, and freshness. Relationship and Changes pages provide the path from a Product to its Variants, Listings, Offers, Reviews, and Store context. A Variant page separates three concerns: * canonical Product and Variant identity; * current Offers, sellers, availability, and source URLs; * observed Offer history with its actual timestamps. In the public API, Variant metadata, current Offers, and history are separate resources so Offers and history can be paged independently. See the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) for exact routes, filters, sort options, and response schemas. ## Run packaged Analyses Explore currently provides four Analyses through the dashboard, public API, and dashboard Agent. | Analysis | Scope | What it answers | | ------------------------ | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | **Price position** | Reference Store, country, currency; condition defaults to new | How the reference Store's lowest available Offer compares with other observed Stores for the same exact Variants | | **Price movements** | Country, currency, observation window; condition defaults to new | Which Listing and seller Offer series increased, decreased, stayed unchanged, or were newly observed | | **Availability changes** | Country and observation window; condition defaults to new | What is currently available, unavailable, or unknown, and which comparable series went out of stock, restocked, appeared, or disappeared | | **Assortment overlap** | Two different Stores and one country | Which exact Variants are shared, reference-only, or comparison-only in the two observed active assortments | Brand, category, and Store filters are available where they preserve the Analysis grain. Countries, currencies, conditions, Listings, and sellers are never combined silently. ## Price position For each exact Variant, each Store contributes its lowest current available Offer. The reference Store is compared with the conventional median of the other Stores. A Variant is comparable only when the reference Store and at least two comparison Stores have qualifying Offers. The Analysis reports the reference price, competitor range and median, price deltas, rank, price index, comparable coverage, freshness, and the Offers used as evidence. It does not recommend a price or infer margin, demand, sales, market share, or MAP compliance. ## Price movements Movement is measured within one Listing, seller, condition, and currency series. The Analysis compares the two latest observations in the selected window and uses earlier history to keep newly observed series separate from ordinary one-observation gaps. A missing later Offer is not a price decrease, and prices in different currencies are not comparable. ## Availability changes Availability keeps four situations distinct: explicitly available, explicitly unavailable, unknown, and no longer observed. Multiple simultaneous currencies do not create different availability series. At Store and Variant grain, a Store is available when any qualifying current Offer is available. Listing removal remains explicit Listing evidence; it is not rewritten as an out-of-stock transition. Explore does not infer units on hand, lost sales, or continuous outage duration between observations. ## Assortment overlap Assortment is the set of distinct exact Variants connected to active Listings for each selected Store and country. Duplicate Listings and marketplace sellers do not increase membership. The result reports shared and Store-only sets, coverage from each side, and Jaccard similarity. A Store-only Variant is an observed gap within the extracted scope. It is not proof of exhaustive catalog absence or a sales opportunity. ## Read an Analysis result Every Analysis response includes: * a stable Analysis id; * the normalized scope and generation time; * `eligible`, `limited`, or `ineligible` status with issue codes; * a summary, coverage, and oldest/newest evidence time; * typed evidence rows and an opaque `next_cursor` when another API page exists. `eligible` means the minimum evidence exists. `limited` means the result is valid but materially constrained by coverage or freshness. `ineligible` means the selected data cannot support the headline metric. An observed zero is not the same as missing evidence. For pageable Analysis routes, summary, coverage, and freshness describe the whole selected Analysis scope; `rows` contains only the current evidence page. On unchanged data, later pages repeat the same scope-level values. Preserve the filters and sort, and pass `next_cursor` back unchanged. Pagination reads live data rather than freezing a transaction across requests. ## Ask with Explore AI Explore AI starts with the connected model rather than a table picker. Ask about products, markets, prices, availability, reviews, or assortment; Extralt loads the relevant entity definitions and relationships, generates SQL, runs it through the read-only organization-scoped service, and persists the question, SQL, result, and status at one dashboard URL. The model defines active Listings, current Offers and Reviews, observed assortment, first-observed evidence, explicit removal, and availability. Query results contain at most 100 rows and are not pageable; a truncated result means the question or generated query should be narrowed. Explore AI is a dashboard surface, not a public v1 endpoint or direct ClickHouse connection. ## Ask through the Agent The dashboard Agent can run the same four packaged Analyses and link to their dedicated pages. It returns the complete status, issues, summary, coverage, and freshness plus a bounded evidence preview, and tells you when more evidence is available on the page. For a custom question, the Agent uses the same Query model, persistence, and result page as Explore AI. See [Using the dashboard Agent](/docs/guides/using-the-agent) for operation and approval boundaries. ## Interpretation boundaries * Results describe the Stores, countries, URLs, and observation times the organization chose to collect, not the entire market. * "Current" means the latest observation represented by the surface, not a continuously synchronized market snapshot. * Matching depends on identifiers and product evidence available during Enrich; exact Variant comparisons do not imply perfect market coverage. * Store means an organization-scoped hostname and country, not a retailer group or legal company. * Explore does not contain sales, revenue, traffic, demand, margin, or market share unless a future data source and contract explicitly add them. Saved or scheduled Analysis configurations, alerts, and dedicated Analysis file exports are not current capabilities. API evidence can be traversed with cursor pagination. Continue with [Query semantics](/docs/data/query-semantics) for the definitions behind current state, time, availability, coverage, and freshness. --- ## Extracting data Create a Robot for a website and country, monitor its build, run ecommerce extraction, and use the resulting Captures. URL: https://extralt.com/docs/guides/extracting-data Extraction has two user-facing resources: * A **Robot** is the stable extraction resource for one host and country. * A **Run** uses a completed Robot to crawl pages and produce Captures. You create the Robot once, wait for its build to complete, then reuse it for manual and scheduled Runs. ## Extraction workflow 1. Create or retrieve the Robot for the target host and country. 2. Monitor that Robot while Extralt generates and validates its crawler and scraper. 3. Start a Run after the Robot reaches `completed`. 4. Monitor the Run and inspect or export its Captures. ## Create a Robot ## Dashboard Go to **Extract > Robots > New**. Enter a product URL from the target site and select the country where Extralt should access it. After you select **Create**, the dashboard opens the Robot details page for the returned Robot ID. This happens whether the Robot was newly created or already existed for that host and country. {/* Screenshot placeholder: Robot creation form with a product URL on nike.com and country US selected. Keep the Robots tabs visible and show List, New, and Details only. */} ## API cURL Python Node.js ```bash export EXTRALT_API_KEY="your-api-key" curl -s -X POST "https://api.extralt.com/v1/extract/robots" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: robot-create-example-1" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example-store.com/products/sample", "country_code": "US" }' | jq ``` ```python import requests API_KEY = "your-api-key" HEADERS = {"Authorization": f"Bearer {API_KEY}"} response = requests.post( "https://api.extralt.com/v1/extract/robots", headers={**HEADERS, "Idempotency-Key": "robot-create-example-1"}, json={ "url": "https://example-store.com/products/sample", "country_code": "US", }, ) response.raise_for_status() robot = response.json() print(robot) ``` ```javascript const API_KEY = "your-api-key"; const headers = { Authorization: `Bearer ${API_KEY}` }; const response = await fetch("https://api.extralt.com/v1/extract/robots", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "robot-create-example-1", }, body: JSON.stringify({ url: "https://example-store.com/products/sample", country_code: "US", }), }); if (!response.ok) throw new Error(await response.text()); const robot = await response.json(); console.log(robot); ``` The response contains the stable Robot ID and its current status: ```json { "id": "", "status": "pending" } ``` * `202 Accepted` means a new Robot was created and its build was queued. * `200 OK` means the Robot already existed for that host and country. Both responses identify the same user-facing resource. There is no separate Robot Build resource. For a compatible covered source, an existing Robot may already be `completed`. Otherwise, Extralt analyzes the source, generates extraction logic, validates it, and compiles it. Build time depends on the source and the validation work required. ## Monitor the Robot build The Robot exposes its build status throughout its lifecycle: | Status | Meaning | | ----------- | ------------------------------------------------------------- | | `pending` | The build is queued | | `building` | Extralt is analyzing the source and preparing the Robot | | `completed` | The Robot is ready for Runs and Schedules | | `failed` | The build failed; `status_reason` contains the failure detail | A Robot build cannot currently be stopped once it has started. ## Dashboard The Robot details page updates as the build moves from `pending` to `building` and then to a final status. Keep this page open to monitor the build, or return to it from the Robots list. {/* Screenshot placeholder: Robot details page for nike_com_US while status is Building. Show the stable Robot ID in the URL, the Name, Runs, Host, Country, and Status fields, and no extraction heatmap yet. */} {/* Screenshot placeholder: Robot details page for a failed Robot. Show the Failed status and a concise status reason so the final failure state is visible. */} ## API Read the Robot by the ID returned from creation: cURL Python Node.js ```bash curl -s "https://api.extralt.com/v1/extract/robots/$ROBOT_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` ```python response = requests.get( f"https://api.extralt.com/v1/extract/robots/{robot['id']}", headers=HEADERS, ) response.raise_for_status() print(response.json()) ``` ```javascript const response = await fetch( `https://api.extralt.com/v1/extract/robots/${robot.id}`, { headers }, ); if (!response.ok) throw new Error(await response.text()); console.log(await response.json()); ``` Poll until the status is `completed` or `failed`. Only `completed` Robots can start Runs or Schedules. ## Robot identity and naming Within an organization, a Robot is unique for a `(host, country)` pair. A leading `www.` is ignored for identity, so `www.nike.com` and `nike.com` in the same country resolve to the same Robot. Robot names are derived and cannot be edited. Extralt removes a leading `www.`, replaces dots with underscores, and appends the uppercase country code. For example, `www.nike.com` in the United States becomes `nike_com_US`. The Robot's `run_count` records how many Runs have been created for it. Each new Run increments that counter and is named `_`, such as `nike_com_US_1`. ## Manage Robots ## Dashboard The Robots list includes Robots in every build status. Its columns are **Name**, **Host**, **Country**, **Language**, **Status**, **Reason**, **Runs**, and **Created**. Select a Robot to view its details or Runs. **Start Run** and **Schedule Run** are available only when the selected Robot is `completed`. Robots cannot be renamed. {/* Screenshot placeholder: Populated Robots list containing pending, building, failed, and completed rows. Use nike_com_US for the completed row, show a non-zero Runs count, keep the current table columns visible, and show no Builds tab or Rename action. */} ## API List all Robots in the organization: cURL ```bash curl -s "https://api.extralt.com/v1/extract/robots" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` `GET /v1/extract/robots/{id}` returns one Robot with its name, host, country, detected language when available, status, status reason, Run count, and timestamps. `DELETE /v1/extract/robots/{id}` returns `204 No Content`. An active build or Run must finish before its Robot can be deleted. Deleting a Robot also removes its Schedules. ## Start a Run ## Dashboard Go to **Extract > Runs > New**, or select a completed Robot in the Robots list and choose **Start Run**. The selector contains only completed Robots. Optionally provide start URLs, a crawl budget, and automatic enrichment. Start URLs must use the selected Robot's host. After you select **Start**, the dashboard opens the new Run's details page. {/* Screenshot placeholder: New Run form with the Robot selector open and nike_com_US selected. Use a dataset that also contains pending, building, and failed Robots, but verify only the completed Robot appears. Show start URLs, crawl budget, and auto-enrich controls. */} ## API cURL Python Node.js ```bash curl -s -X POST "https://api.extralt.com/v1/extract/runs" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: run-create-example-1" \ -H "Content-Type: application/json" \ -d '{ "robot_id": "'$ROBOT_ID'", "start_urls": ["https://example-store.com/collections/shoes"], "budget": 100, "auto_enrich": false }' | jq ``` ```python response = requests.post( "https://api.extralt.com/v1/extract/runs", headers={**HEADERS, "Idempotency-Key": "run-create-example-1"}, json={ "robot_id": robot["id"], "start_urls": ["https://example-store.com/collections/shoes"], "budget": 100, "auto_enrich": False, }, ) response.raise_for_status() run = response.json() print(run) ``` ```javascript const response = await fetch("https://api.extralt.com/v1/extract/runs", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "run-create-example-1", }, body: JSON.stringify({ robot_id: robot.id, start_urls: ["https://example-store.com/collections/shoes"], budget: 100, auto_enrich: false, }), }); if (!response.ok) throw new Error(await response.text()); const run = await response.json(); console.log(run); ``` The response is `202 Accepted` with `{ "id": "" }`. | Parameter | Required | Description | | ------------- | -------- | --------------------------------------------------------------------------------- | | `robot_id` | Yes | A completed Robot in your organization | | `start_urls` | No | Crawl entry points on the Robot's host. The Robot uses its defaults when omitted. | | `budget` | No | Maximum number of Captures to produce | | `auto_enrich` | No | Start an Enrichment after the Run completes. Defaults to `false`. | ## Monitor and manage Runs | Status | Meaning | | ------------ | ------------------------------------------ | | `pending` | The Run is queued | | `starting` | The Run is starting | | `running` | The Robot is crawling and extracting | | `restarting` | A restart is being applied | | `completed` | The Run finished successfully | | `failed` | The Run encountered an unrecoverable error | | `stopped` | The Run was stopped manually | ## Dashboard The Runs list shows **Name**, **Robot**, **Status**, **Reason**, **Budget**, **Extracted**, **Started**, and **Duration**. Select a Run to view its details or Captures. You can stop a `pending`, `starting`, `restarting`, or `running` Run. You can restart only a `stopped` or `failed` Run, optionally with a new budget. A restart keeps the same Run ID and name. {/* Screenshot placeholder: Populated Runs list for nike_com_US with names nike_com_US_1 and nike_com_US_2. Include useful completed, running, and failed states and show the current Reason, Started, and Duration columns. */} ## API Read a Run until it reaches `completed`, `failed`, or `stopped`: cURL ```bash curl -s "https://api.extralt.com/v1/extract/runs/$RUN_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` Stop an active Run: cURL ```bash curl -s -X POST "https://api.extralt.com/v1/extract/runs/$RUN_ID/stop" \ -H "Authorization: Bearer $EXTRALT_API_KEY" ``` Restart a stopped or failed Run with an optional replacement budget: cURL ```bash curl -s -X POST "https://api.extralt.com/v1/extract/runs/$RUN_ID/restart" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: run-restart-example-1" \ -H "Content-Type: application/json" \ -d '{ "budget": 200 }' | jq ``` Stop returns `204 No Content`. Restart returns `202 Accepted` with the same Run ID. ## Concurrency and credits | Plan | Concurrent Runs | | --------- | --------------- | | **Start** | 1 | | **Scale** | Unlimited | Each successful product-page Capture costs 2 credits. A new Run requires enough credits for at least one Capture. ## Use the Captures After the Run starts producing Captures, select **View Captures** in the dashboard. You can filter by Robot or Run and export the result as JSONL or Parquet. See [Working with Captures](/docs/guides/working-with-captures) for browsing and export options, or [Schedules](/docs/guides/schedules) to create recurring Runs. --- ## Imports Upload catalog files into Extract, validate them, and turn valid product data into Captures for Enrich and Explore. URL: https://extralt.com/docs/guides/imports Imports let you bring first-party catalog data into Extralt without crawling your own storefront first. A run crawls ecommerce pages. An import uploads catalog data you already have. Both produce Captures, and Captures move through the same Enrich and Explore pipeline. ## When to use imports Use imports when you want your own product catalog inside Extralt: * Seed Extralt with your current product data * Compare your catalog against open-web competitor observations * Enrich your own products with the same taxonomy, attributes, and signals as extracted products * Include your catalog in the same downstream views as extracted observations Imports are not a separate product model. They are another way to create captures. ## Creating an import ## Dashboard Navigate to **Extract > Imports > New**. Choose a catalog file, confirm the country and language, then upload it. The import appears in **Extract > Imports > List** with its current status, success count, error count, and status message. Supported source files currently include JSON, JSONL, and CSV. The file should contain enough product data to build valid captures: product titles, images, variants or SKUs, prices, currency, and stable product or SKU identifiers where available. ## API The dashboard sends the file to the Extract API. API clients can use the same import endpoint under `/v1/extract/imports`. Send the source file as the request body and metadata as query parameters: ```bash curl -s -X POST \ "https://api.extralt.com/v1/extract/imports?file_name=catalog.csv&country_code=US&language_code=en&source_host=shop.example" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: import-catalog-example-1" \ -H "Content-Type: text/csv" \ --data-binary @catalog.csv | jq ``` The response is `202 Accepted` with `{ "id": "" }`. Poll `GET /v1/extract/imports/{id}`, then list Captures with `GET /v1/extract/captures?import_id={id}`. Retry an interrupted upload with the same file, metadata, and `Idempotency-Key`. Creating a new Import requires an active subscription; replaying a completed request with the same key still returns its original result. ## Validation Imports use the same capture quality gate as crawled data. Extralt does not force incomplete catalog rows into captures. An import can fail validation when the source data is too sparse or ambiguous, for example: * no usable product title * no product image * no variant or SKU structure * no positive price * no currency * rows that cannot be mapped to stable products * nested data where products, variants, prices, or stock cannot be joined safely When validation fails, the import status includes a message explaining what was missing or invalid. Imported data should be clean enough to represent products on its own. If the file is only an inventory delta, price list, or partial export, it may need to be joined upstream before importing. ## After import Once an import completes, open **Extract > Captures** and filter by the import job. Imported captures can then be enriched like captures from a crawl run. The downstream model is the same: | Stage | Imported catalog data becomes | | ------- | --------------------------------------------------------------------------- | | Extract | Captures | | Enrich | Items plus Listings, Offers, Reviews, Stores, Variants, and product matches | | Explore | Implemented overview, facets, current-market, and Variant views | --- ## Scheduling Runs Reuse a completed Robot on a cadence and manage the resulting recurring Runs. URL: https://extralt.com/docs/guides/schedules A Schedule creates recurring Runs with a completed Robot. Each scheduled Run uses the same inputs and follows the Robot's Run-name sequence. If you still need to create or complete a Robot, start with [Extracting data](/docs/guides/extracting-data). ## Create a Schedule ## Dashboard Navigate to **Extract > Schedules** and click **New Schedule**. 1. Select the completed Robot to use 2. Set the cadence (e.g. every 1 day, every 6 hours, every 1 week) 3. Optionally provide start URLs and a budget 4. Click **Create** A name is generated from the cadence and Robot, such as `Daily nike_com_US run`. You can provide a different Schedule name without renaming the Robot. The Robot selector shows only `completed` Robots. {/* Screenshot placeholder: New Schedule form with the Robot selector open and nike_com_US selected. Use a dataset with other non-completed Robots and verify they are absent. Show the optional name, cadence, start URLs, crawl budget, and auto-enrich controls. */} ## API cURL Python Node.js ```bash export EXTRALT_API_KEY="your-api-key" curl -s -X POST "https://api.extralt.com/v1/extract/schedules" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: schedule-create-example-1" \ -H "Content-Type: application/json" \ -d '{ "robot_id": "your-robot-id", "cadence": { "interval_amount": 1, "interval_unit": "day" }, "start_urls": ["https://example-store.com/products"], "budget": 50 }' | jq ``` ```python import requests API_KEY = "your-api-key" HEADERS = {"Authorization": f"Bearer {API_KEY}"} response = requests.post( "https://api.extralt.com/v1/extract/schedules", headers={**HEADERS, "Idempotency-Key": "schedule-create-example-1"}, json={ "robot_id": "your-robot-id", "cadence": { "interval_amount": 1, "interval_unit": "day", }, "start_urls": ["https://example-store.com/products"], "budget": 50, }, ) schedule = response.json() print(f"Schedule ID: {schedule['id']}") ``` ```javascript const API_KEY = "your-api-key"; const headers = { Authorization: `Bearer ${API_KEY}` }; const response = await fetch("https://api.extralt.com/v1/extract/schedules", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "schedule-create-example-1", }, body: JSON.stringify({ robot_id: "your-robot-id", cadence: { interval_amount: 1, interval_unit: "day", }, start_urls: ["https://example-store.com/products"], budget: 50, }), }); const schedule = await response.json(); console.log(`Schedule ID: ${schedule.id}`); ``` The response is `201 Created` with `{ "id": "" }`. ## Parameters | Parameter | Required | Description | | ------------------------- | -------- | ---------------------------------------------------------------------------------------------------- | | `robot_id` | Yes | A completed Robot in your organization | | `cadence.interval_amount` | Yes | Number of intervals between runs (e.g. 1, 6, 12) | | `cadence.interval_unit` | Yes | `hour`, `day`, `week`, or `month` | | `name` | No | Schedule display name. Generated from cadence and Robot when omitted. | | `start_urls` | No | URLs to crawl. Must match the Robot's host. | | `budget` | No | Maximum number of Captures to produce per run. Each successful product-page Capture costs 2 credits. | | `auto_enrich` | No | If `true`, automatically run enrichment after each scheduled run. Defaults to `false`. | Every scheduled Run increments the Robot's `run_count`. For example, if the latest manual Run is `nike_com_US_2`, the next scheduled Run is `nike_com_US_3`. ## Cadence options Schedules support flexible cadence intervals: | Example | interval\_amount | interval\_unit | | ------------- | ---------------- | -------------- | | Every hour | 1 | `hour` | | Every 6 hours | 6 | `hour` | | Daily | 1 | `day` | | Every 3 days | 3 | `day` | | Weekly | 1 | `week` | | Monthly | 1 | `month` | ## Manage Schedules ## Dashboard Navigate to **Extract > Schedules** to see all your schedules in a table. {/* Screenshot placeholder: Populated Schedules list using nike_com_US. Include active, user-paused, and system-paused examples and show Name, Robot, Cadence, Next Run, Last Run, and Status. */} The table displays: | Column | Description | | ------------ | --------------------------------------------------------------- | | **Name** | Schedule name | | **Robot** | Which Robot the Schedule uses | | **Cadence** | How often the Schedule creates a Run | | **Next run** | When the next Run will be created | | **Last run** | When the last Run was created | | **Status** | Active, Paused, Paused (no credits), or Paused (payment failed) | Actions available: * **Pause** / **Resume**: toggle the schedule on or off * **Edit**: change the name, cadence, start URLs, or budget * **Delete**: remove the schedule permanently ## API cURL ```bash # List schedules curl -s "https://api.extralt.com/v1/extract/schedules" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq # Update a schedule (returns 204 No Content) curl -s -X PATCH "https://api.extralt.com/v1/extract/schedules/$SCHEDULE_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "cadence": { "interval_amount": 1, "interval_unit": "week" } }' # Delete a schedule (returns 204 No Content) curl -s -X DELETE "https://api.extralt.com/v1/extract/schedules/$SCHEDULE_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" ``` The editable fields are `cadence`, `name`, `robot_id`, `budget`, `start_urls`, and `auto_enrich`. A replacement `robot_id` must identify another completed Robot. The list and read responses use `snake_case` and nest the Run inputs: `{ id, name, robot_id, robot_name, enabled, cadence: { interval_amount, interval_unit }, config: { start_urls, budget, auto_enrich }, next_run_at, last_run_at, ... }`. ## Pause and resume You can pause a Schedule at any time. A user-paused Schedule stops creating Runs until you resume it. ## Dashboard Select a Schedule in the list, then choose **Pause** or **Resume**. A Schedule paused because of credits or payment cannot be resumed manually; Extralt resumes it when the underlying issue is resolved. ## API cURL Python Node.js ```bash # Pause curl -s -X POST "https://api.extralt.com/v1/extract/schedules/$SCHEDULE_ID/pause" \ -H "Authorization: Bearer $EXTRALT_API_KEY" # Resume curl -s -X POST "https://api.extralt.com/v1/extract/schedules/$SCHEDULE_ID/resume" \ -H "Authorization: Bearer $EXTRALT_API_KEY" ``` ```python # Pause requests.post( f"https://api.extralt.com/v1/extract/schedules/{schedule_id}/pause", headers=HEADERS, ) # Resume requests.post( f"https://api.extralt.com/v1/extract/schedules/{schedule_id}/resume", headers=HEADERS, ) ``` ```javascript // Pause await fetch(`https://api.extralt.com/v1/extract/schedules/${scheduleId}/pause`, { method: "POST", headers, }); // Resume await fetch(`https://api.extralt.com/v1/extract/schedules/${scheduleId}/resume`, { method: "POST", headers, }); ``` ## Credits and automatic pauses Scheduled Runs consume credits the same way as manual Runs: **2 credits per successful product-page Capture**. Category, search, collection, and other discovery pages do not consume credits. If your organization runs out of credits, all active schedules automatically pause. They show a **Paused (no credits)** status in the dashboard. When credits become available again through a purchase or billing cycle, Extralt automatically resumes Schedules paused for `no_credits`. Schedules paused after a payment failure also resume automatically after the payment issue is resolved. A Schedule that you paused manually remains paused. See [Credits & Billing](/docs/guides/credits-billing) for more on credit management. ## Concurrency If a Schedule's previous Run is still active when the next Run is due, the Schedule skips that execution and waits for the next interval. Runs from the same Schedule do not overlap. --- ## Connect through MCP Connect ChatGPT, Claude, Codex, Cursor, or another compatible MCP client to Extralt with OAuth. URL: https://extralt.com/docs/guides/using-mcp Connect a compatible agent to operate Extralt and inspect your organization's ecommerce data. Use this MCP endpoint: ``` https://api.extralt.com/mcp ``` MCP uses browser OAuth rather than an API key. During authorization, sign in to Extralt, select the organization the client should use, and approve access. The selected organization is taken from the OAuth grant; tool inputs never ask for an organization ID. ## Connect a client Extralt advertises both CIMD and dynamic client registration, so supported clients can register automatically. You do not need to create an OAuth client, enter a client secret, or configure scopes manually. ## Codex Add the server from a terminal: ```bash codex mcp add extralt --url https://api.extralt.com/mcp ``` If Codex does not open the authorization flow during setup, run: ```bash codex mcp login extralt ``` See the [Codex MCP documentation](https://developers.openai.com/codex/mcp/) for client settings. ## ChatGPT Enable developer mode, create an app from the Extralt MCP URL, choose OAuth with CIMD, scan the tools, then complete authorization. Availability and admin approval depend on your ChatGPT workspace. See the [ChatGPT developer-mode guide](https://developers.openai.com/api/docs/guides/developer-mode). ## Claude Open **Customize > Connectors**, add a custom connector with the Extralt MCP URL, and leave the optional OAuth client ID and secret blank. Select **Connect** to authorize it. See the [Claude connector guide](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp). ## Cursor Add the server to the project `.cursor/mcp.json` or your global MCP configuration, then authenticate it from Cursor's MCP settings: ```json { "mcpServers": { "extralt": { "url": "https://api.extralt.com/mcp" } } } ``` See the [Cursor MCP documentation](https://prod.cursor.com/docs/mcp) for the current configuration location and controls. To use a different organization later, reauthorize the Extralt connection in your MCP client and select the other organization on the consent screen. ## Available capabilities | Stage | What an agent can do | | ----------- | -------------------------------------------------------------------------------------------------------- | | **Extract** | Create and inspect Robots; manage Runs and Schedules; create Imports; list, count, and export Captures | | **Enrich** | Start, inspect, and stop Enrichments; list and inspect enriched Items | | **Explore** | Inspect coverage, facets, current markets, Variants, Offers, and history; run the four packaged Analyses | Tools use the same resource names as the API: `create_robot`, `list_robots`, `create_run`, `get_run`, `restart_run`, and `list_captures`, for example. Your client discovers the complete tool catalog and input schemas from the MCP server. The tools use the same capability services and authorization rules as API v1. ## Long-running work and exports Robot creation, Extract Runs, Imports, and Enrichments return a durable ID immediately. The result tells the agent which status tool to poll. Runs and Enrichments can be stopped; Robot builds and Imports continue until they complete or fail. Capture exports return a short-lived download URL for JSONL or Parquet. The URL expires after 15 minutes and can be passed directly to a download client such as `curl`. ## Access rules An active organization can use read and write tools. During the read-only subscription grace period, clients can inspect and export data, stop active work, pause Schedules, and replay a completed idempotent request, but they cannot start new work. Suspended organizations cannot use MCP data tools. MCP calls are direct operations. Review write and destructive tool calls in your client before allowing them. The REST API remains available separately and uses organization API keys. Its [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) describes the REST contract, not MCP tool schemas. --- ## Using the dashboard Agent Use the dashboard Agent to inspect operations, analyze product data, and prepare approval-gated Robot, Extract, Enrich, and Schedule work. URL: https://extralt.com/docs/guides/using-the-agent The dashboard Agent is a conversational interface to capabilities that already exist in the dashboard. It can inspect operations, run Explore Analyses, answer custom data questions, and prepare state-changing work for approval. Its answers link back to the relevant page so the result remains inspectable. ## Inspect operations The Agent can list and inspect organization-scoped: * Robots; * Extract Runs; * Schedules; * Enrichments; * Imports. Use the resource's name when possible. A page context such as "this Run" can resolve an identifier, but the Agent does not silently use an unrelated scope. ## Analyze product data The Agent has two analytical paths. ## Packaged Analyses For Price position, Price movements, Availability changes, or Assortment overlap, the Agent runs the same contract as the dedicated Explore page and public API. It preserves the Analysis status, limitations, summary, coverage, freshness, and dashboard URL. The chat response includes at most 20 evidence rows. When more evidence exists, the Agent says so and links to the Analysis page rather than presenting the preview as exhaustive. ## Explore AI For other factual questions, the Agent can query: * **Captures** for raw Extract output, optionally scoped to one Run or Import; * **Items** for normalized page-grain Enrich output, optionally scoped to one Enrichment; * **Explore** for questions across connected Products, Variants, Listings, Offers, Reviews, and Stores. The Agent first loads the data model for that surface, then generates and runs one bounded read query. The persisted result retains the question, generated SQL, rows, truncation state, and a link to the corresponding dashboard Query artifact on its AI page. Results contain at most 100 rows and are not pageable. Use a packaged Analysis when its stable definition answers the question. Use Explore AI for exploratory groupings, counts, and evidence that do not have a packaged contract. ## Prepare operations for approval The Agent can prepare: * a Robot build for a domain and country explicitly supplied by the user; * an Extract Run using a selected existing Robot; * a recurring Schedule using a selected existing Robot; * a Run or Schedule that first builds a Robot when the supplied domain has no matching Robot; * an Enrichment for an existing completed Extract Run; * an Extract Run followed by Enrich when both budgets are explicit. Before proposing work, it resolves the relevant existing resources and keeps the domain, country, URLs, budgets, cadence, and Enrich choice visible. It does not discover or infer a new domain that the user did not supply. Imports are read-only in the Agent. Create or retry them from their dedicated dashboard or API surface. ## Approval boundary Preparing an operation does not execute it. The dashboard displays the exact steps and inputs, and state-changing work starts only after the user selects **Approve**. Rejecting or superseding a proposal does not consume Extract or Enrich credits. Interrupted approved work can be retried from its operation state. The workflow keeps the approved inputs and avoids duplicating a completed step. ## Ask precise questions Use the product terms that match the required grain: * **Capture** for one extracted or imported page record; * **Item** for one normalized page-grain Enrich result; * **Product** for a canonical family; * **Variant** for one exact cross-store configuration; * **Listing** for one Store SKU; * **Offer** for one seller, price, and availability observation. Examples: * "Which Captures in this Run have no brand?" * "Group these Items by category and brand." * "Compare Nike price position for this Store in the US in USD." * "Show current available Offer count and median price by Store and currency." * "Prepare a 100-Capture Run for the confirmed Nike US Robot, then Enrich up to 100 Captures." ## Boundaries The Agent cannot bypass organization isolation, ClickHouse's read-only role, subscription access, execution limits, or dashboard approval. Explore AI does not expose arbitrary physical or internal tables and cannot write data. The underlying dataset contains observed ecommerce product evidence. The Agent must qualify or reject conclusions about sales, demand, traffic, margin, market share, sentiment, or complete market coverage when those facts are not present. See [Exploring data](/docs/guides/exploring-data) for the four Analysis contracts and [Access surfaces](/docs/data/access-surfaces) for the dashboard, API, export, Query, and Agent boundaries. --- ## Working with Captures Browse, filter, and export extracted ecommerce data from the Extralt dashboard or API. Search captures, view details, and download results. URL: https://extralt.com/docs/guides/working-with-captures A Capture is one structured product record produced by a successful product-page extraction or valid Import row. It retains the source URL or import lineage and the time the source was observed. ## Browsing captures ## • Dashboard Navigate to **Extract > Captures** to view your extracted data. Use the filter dropdown to choose how to view captures: * **By run name**: select a specific run to see its captures. * **By robot name**: select a robot to see captures across all of its runs. An additional **Run Name** column appears so you can tell which run produced each capture. The table displays **Image**, **Brand**, **Title**, **Price**, **Available**, **SKUs**, **URL**, and **Extracted At** for each capture. Click any row to open a detail panel with two tabs: * **Product** — an interactive product page view showing images, options, pricing, description, and more. * **Raw Data** — the full JSON extraction data with syntax highlighting. ## • API List captures from a specific run: cURL Python Node.js ```bash export EXTRALT_API_KEY="your-api-key" curl -s "https://api.extralt.com/v1/extract/captures?run_id=$RUN_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` ```python import requests API_KEY = "your-api-key" HEADERS = {"Authorization": f"Bearer {API_KEY}"} response = requests.get( "https://api.extralt.com/v1/extract/captures", headers=HEADERS, params={"run_id": run_id}, ) data = response.json() for capture in data["data"]: print(f"{capture['title']} - {capture['url']}") ``` ```javascript const API_KEY = "your-api-key"; const headers = { Authorization: `Bearer ${API_KEY}` }; const response = await fetch( `https://api.extralt.com/v1/extract/captures?run_id=${runId}`, { headers }, ); const data = await response.json(); data.data.forEach((c) => { console.log(`${c.title} - ${c.url}`); }); ``` The response is `{ data, next_cursor }`. The default page size is 100 and the maximum is 1,000. See [Common Patterns](/docs/using-the-api/common-patterns#pagination) for paginating through large result sets with `next_cursor`. ## Extraction data schema Every Capture follows the same base product-data contract across sources. ```json { "id": "019d3ec3-cf96-7520-bc31-1474206e06ed", "url": "https://www.nike.com/t/dna-mens-dri-fit-basketball-shorts-hVGm16/HV1878-350", "extracted_at": 1774874512106, "product_id": "HV1878-350", "handle": "dna-mens-dri-fit-basketball-shorts-hVGm16", "group_id": "hVGm16", "title": "Nike DNA", "subtitle": "Men's Dri-FIT Basketball Shorts", "brand": "Nike", "breadcrumbs": "Men > Basketball > Shorts", "description": "Built for the court, ready for anywhere. These lightweight-yet-durable basketball shorts help keep you cool with our sweat-wicking Dri-FIT technology.", "publication_date": "2025-10-02T07:00:00.000Z", "gender": "MEN", "age_group": "Adult", "ratings_average": null, "ratings_count": 0, "ratings_scale": 5, "min_price": 41.97, "max_price": 41.97, "currency": "USD", "available": true, "sku_count": 7, "image_url": "https://static.nike.com/a/images/t_default/326dc2d4-a16d-4433-93d7-8d6f8313d4d0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "categories": [ "Men", "Basketball", "Shorts" ], "tags": [ "Basketball", "Dri-FIT", "Shorts", "Men" ], "images": [ { "url": "https://static.nike.com/a/images/t_default/326dc2d4-a16d-4433-93d7-8d6f8313d4d0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 1, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/e2c6c1aa-6d12-46b9-9385-d76bd4fa30e0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 3, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/38d8c21c-c8dd-466b-949c-92fdfcd0320b/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 4, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/79d907aa-1763-4af7-a1bf-99f5fc30acc4/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 5, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/1cd3d1a3-fea9-4295-bf8a-f3d6d59f2d47/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 6, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/3cf19355-4f26-4faf-b658-581297b87e9c/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 7, "sku_ids": [ "HV1878-350" ] } ], "videos": null, "physical_measurements": null, "properties_dict": { "Style": "HV1878-350", "Shown": "Chlorophyll/Black" }, "properties_list": [ "Recycled Materials", "Designed for Basketball", "Unlined", "Lightweight, sweat-wicking fabric with mesh and smooth interior", "Side pockets and zippered utility pocket large enough for a phone", "Elastic waistband with drawcord", "Body: 100% polyester. Pocket bags: 100% polyester.", "Machine wash", "Imported", "Shown: Chlorophyll/Black", "Style: HV1878-350" ], "options": { "opt1": { "name": "Color", "values": [ "Chlorophyll/Black" ] }, "opt2": { "name": "Size", "values": [ "S", "M", "L", "XL", "2XL", "3XL", "4XL" ] }, "opt3": null }, "skus": [ { "id": "90c9f2c2-d984-5cc2-a2a0-89deac668eb3", "title": null, "identifiers": { "gtin": "00198482162061", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "S", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "032621f4-8f17-5716-932d-a93b0d1dfc4a", "title": null, "identifiers": { "gtin": "00198481839179", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "M", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "a73069dc-17b2-5dc7-b5cc-e78c9674d8cd", "title": null, "identifiers": { "gtin": "00198481982455", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "L", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "417e97e7-c31c-5ac0-999c-5b6779ba831d", "title": null, "identifiers": { "gtin": "00198482264932", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "42484108-e343-520f-9ed1-1ca72a301174", "title": null, "identifiers": { "gtin": "00198481731473", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "2XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "Limited stock available" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "179d2b07-b59e-5a7d-912f-cebf81b1d13f", "title": null, "identifiers": { "mpn": "HV1878-350", "gtin": "00198482258597" }, "opt1": "Chlorophyll/Black", "opt2": "3XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": false, "quantity": "Out of stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "fad73aae-e6b1-58ac-83a3-f17125c0b3b2", "title": null, "identifiers": { "gtin": "00198482211318", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "4XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": false, "quantity": "Out of stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] } ] } ``` **Key fields:** | Field | Description | | --------------------------------------------------- | ---------------------------------------------------------------------------------------- | | `product_id` | Primary product identifier on the site (product handle, ASIN, etc.) | | `group_id` | Groups related captures for the same source product family (e.g., different color pages) | | `title`, `brand`, `description` | Core product identity | | `image_url` | Primary product image URL | | `images` | Product images with position and optional SKU association | | `min_price`, `max_price`, `currency` | Price range across all SKUs | | `available` | Whether any SKU is currently in stock | | `sku_count` | Total number of purchasable SKUs | | `properties_dict` | Structured attributes as key-value pairs (material, closure, etc.) | | `properties_list` | Unstructured features and claims (bullet points from the product page) | | `ratings_average`, `ratings_count`, `ratings_scale` | Rating metrics | | `options` | Up to 3 option axes (e.g., Color, Size) with all available values | | `skus` | One entry per purchasable option combination, each with identifiers and offers | | `skus[].identifiers` | GTIN, SKU, MPN, and other identifiers for this purchasable SKU | | `skus[].offers` | Price, availability, condition, and seller for each offer | | `skus[].offers[].seller_type` | `1p` (marketplace selling directly), `3p` (third-party seller), or null | The Capture contract is stable across sources, but field population depends on what the page exposes and what the Robot can validate. Use the OpenAPI Capture schema for requiredness and types; do not treat an absent source fact as a measured zero. ## Exporting captures ## • Dashboard Once data is loaded, a download button appears in the filter bar. Click it and choose a format: * **JSONL**: one JSON object per line, with fields for `id`, `url`, `title`, `extracted_at`, `robot_name`, `run_name`, and the full product data. Good for scripting, analysis, and importing into other tools. * **Parquet**: columnar format preserving all capture fields. Ideal for data pipelines, DuckDB queries, and pandas DataFrames. ## • API For bulk download, use the export endpoint. It streams all captures from the run as a single file with `Content-Disposition: attachment`. The `format` query parameter accepts `parquet` (default) or `jsonl`. cURL Python Node.js ```bash # Parquet (default) curl -sL "https://api.extralt.com/v1/extract/captures/export?run_id=$RUN_ID&format=parquet" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -o captures.parquet # JSONL curl -sL "https://api.extralt.com/v1/extract/captures/export?run_id=$RUN_ID&format=jsonl" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -o captures.jsonl ``` ```python with requests.get( "https://api.extralt.com/v1/extract/captures/export", headers=HEADERS, params={"run_id": run_id, "format": "parquet"}, # or "jsonl" stream=True, ) as response: response.raise_for_status() with open("captures.parquet", "wb") as f: for chunk in response.iter_content(chunk_size=64 * 1024): f.write(chunk) ``` ```javascript import { writeFile } from "node:fs/promises"; const response = await fetch( `https://api.extralt.com/v1/extract/captures/export?run_id=${runId}&format=parquet`, // or format=jsonl { headers }, ); const buffer = Buffer.from(await response.arrayBuffer()); await writeFile("captures.parquet", buffer); ``` --- ## Documentation Build and operate ecommerce product datasets with guides for extraction, enrichment, analysis, APIs, exports, and dashboard workflows. URL: https://extralt.com/docs Extralt goes beyond ecommerce scraping. Extract public product and catalog pages, enrich the resulting Captures into normalized Items, connect records across stores, and inspect the customer dataset through the dashboard, API, and MCP. The documentation separates three things that are easy to confuse: * **operations** such as Robots, Runs, Schedules, Imports, and Enrichments; * **data** such as Captures, Items, Products, Variants, Listings, Offers, Reviews, Stores, and Changes; * **access surfaces** such as dashboard views, API resources, exports, OAuth-authenticated MCP tools, dashboard AI queries, and the dashboard agent. ## Getting started New to Extralt? Start with the introduction, then follow the guides for account setup, robots, imports, and scheduling. ## Key concepts The platform follows three stages: **Extract** collects ecommerce page data as Captures, **Enrich** produces normalized Items and publishes their cross-store relationships, and **Explore** turns that connected model into evidence views, four Analyses, custom Query results, and Agent answers. --- ## Core concepts Understand the difference between extraction operations, Captures, enriched Items, and the analytical entities published by Enrich. URL: https://extralt.com/docs/introduction/core-concepts Extralt has two related models. The **control plane** manages work: Robots, Runs, Schedules, Imports, and Enrichments. The **data plane** stores the result: Captures, Items, and Enrich-published analytical entities. Do not use these concepts interchangeably. In particular, a Robot is extraction tooling for a host and country. A Store is an analytical `host × country` entity in the customer dataset. ## Robot A Robot is the stable extraction resource for one host and country. Its status tracks creation of the internal crawler and scraper from `pending` through `building` to `completed` or `failed`. Users create, inspect, and run the Robot; the internal components are not separate dashboard or API resources. * One Robot per organization, host, and country combination * The Robot ID remains stable throughout the build and later Runs * Only completed Robots can start Runs or Schedules * Robot names are derived from host and country and cannot be edited * `run_count` records how many Runs have been created for the Robot in the API ## Run A Run is an extraction job. You select a completed Robot, optionally provide start URLs and a budget, and the Robot crawls the site to produce Captures from product pages. **Run lifecycle:** 1. **Pending** -> queued for execution 2. **Starting** -> run is starting 3. **Running** -> actively crawling and extracting 4. **Completed** -> finished successfully 5. **Failed** -> encountered an unrecoverable error 6. **Stopped** -> manually stopped by the user Each successful product-page Capture in a Run costs **2 credits**. Category, search, collection, and other discovery pages do not consume credits. Run names combine the Robot name and its next counter, such as `nike_com_US_1`. See [Extracting data](/docs/guides/extracting-data) for the complete Robot and Run lifecycle. ## Schedule A Schedule automates recurring extraction. It links a completed Robot to a cadence (for example, every hour, day, or week) and creates Runs at that interval. * User-paused Schedules remain paused until resumed * Schedules paused for credits or payment resume when the issue is resolved * Scheduled Runs consume credits and increment the Robot's Run counter like manual Runs See [Schedules](/docs/guides/schedules) for creation and management. ## Import An import is an Extract job that turns uploaded catalog data into captures. Runs crawl ecommerce pages. Imports ingest product data you already have. Use imports when you want your own catalog inside the same pipeline as open-web observations. A valid import produces captures that can be enriched and explored like captures from a run. **Import lifecycle:** 1. **Pending** -> queued for processing 2. **Running** -> validating and converting the source file 3. **Completed** -> finished successfully 4. **Validation failed** -> the source file did not contain enough clean product data 5. **Failed** -> encountered an unrecoverable error See [Imports](/docs/guides/imports) for dashboard upload and validation behavior. ## Capture A capture is a single structured product data record from a run or import. You can browse and export captures in the dashboard, or fetch them programmatically via the API. ```json { "id": "019d3ec3-cf96-7520-bc31-1474206e06ed", "url": "https://www.nike.com/t/dna-mens-dri-fit-basketball-shorts-hVGm16/HV1878-350", "extracted_at": 1774874512106, "product_id": "HV1878-350", "handle": "dna-mens-dri-fit-basketball-shorts-hVGm16", "group_id": "hVGm16", "title": "Nike DNA", "subtitle": "Men's Dri-FIT Basketball Shorts", "brand": "Nike", "breadcrumbs": "Men > Basketball > Shorts", "description": "Built for the court, ready for anywhere. These lightweight-yet-durable basketball shorts help keep you cool with our sweat-wicking Dri-FIT technology.", "publication_date": "2025-10-02T07:00:00.000Z", "gender": "MEN", "age_group": "Adult", "ratings_average": null, "ratings_count": 0, "ratings_scale": 5, "min_price": 41.97, "max_price": 41.97, "currency": "USD", "available": true, "sku_count": 7, "image_url": "https://static.nike.com/a/images/t_default/326dc2d4-a16d-4433-93d7-8d6f8313d4d0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "categories": [ "Men", "Basketball", "Shorts" ], "tags": [ "Basketball", "Dri-FIT", "Shorts", "Men" ], "images": [ { "url": "https://static.nike.com/a/images/t_default/326dc2d4-a16d-4433-93d7-8d6f8313d4d0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 1, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/e2c6c1aa-6d12-46b9-9385-d76bd4fa30e0/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 3, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/38d8c21c-c8dd-466b-949c-92fdfcd0320b/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 4, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/79d907aa-1763-4af7-a1bf-99f5fc30acc4/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 5, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/1cd3d1a3-fea9-4295-bf8a-f3d6d59f2d47/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 6, "sku_ids": [ "HV1878-350" ] }, { "url": "https://static.nike.com/a/images/t_default/3cf19355-4f26-4faf-b658-581297b87e9c/M+NK+DF+DNA+8IN+SHORT+AOP.png", "position": 7, "sku_ids": [ "HV1878-350" ] } ], "videos": null, "physical_measurements": null, "properties_dict": { "Style": "HV1878-350", "Shown": "Chlorophyll/Black" }, "properties_list": [ "Recycled Materials", "Designed for Basketball", "Unlined", "Lightweight, sweat-wicking fabric with mesh and smooth interior", "Side pockets and zippered utility pocket large enough for a phone", "Elastic waistband with drawcord", "Body: 100% polyester. Pocket bags: 100% polyester.", "Machine wash", "Imported", "Shown: Chlorophyll/Black", "Style: HV1878-350" ], "options": { "opt1": { "name": "Color", "values": [ "Chlorophyll/Black" ] }, "opt2": { "name": "Size", "values": [ "S", "M", "L", "XL", "2XL", "3XL", "4XL" ] }, "opt3": null }, "skus": [ { "id": "90c9f2c2-d984-5cc2-a2a0-89deac668eb3", "title": null, "identifiers": { "gtin": "00198482162061", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "S", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "032621f4-8f17-5716-932d-a93b0d1dfc4a", "title": null, "identifiers": { "gtin": "00198481839179", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "M", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "a73069dc-17b2-5dc7-b5cc-e78c9674d8cd", "title": null, "identifiers": { "gtin": "00198481982455", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "L", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "417e97e7-c31c-5ac0-999c-5b6779ba831d", "title": null, "identifiers": { "gtin": "00198482264932", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "In stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "42484108-e343-520f-9ed1-1ca72a301174", "title": null, "identifiers": { "gtin": "00198481731473", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "2XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": true, "quantity": "Limited stock available" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "179d2b07-b59e-5a7d-912f-cebf81b1d13f", "title": null, "identifiers": { "mpn": "HV1878-350", "gtin": "00198482258597" }, "opt1": "Chlorophyll/Black", "opt2": "3XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": false, "quantity": "Out of stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] }, { "id": "fad73aae-e6b1-58ac-83a3-f17125c0b3b2", "title": null, "identifiers": { "gtin": "00198482211318", "mpn": "HV1878-350" }, "opt1": "Chlorophyll/Black", "opt2": "4XL", "opt3": null, "offers": [ { "price": { "amount": 41.97, "full_amount": 60, "currency": "USD" }, "availability": { "in_stock": false, "quantity": "Out of stock" }, "condition": "new", "seller": "Nike", "seller_type": "1p" } ] } ] } ``` See [Working with Captures](/docs/guides/working-with-captures#extraction-data-schema) for the full schema reference. ## Enrichment and Item An Enrichment processes Captures from an Extract Run. Each successfully processed Capture produces one page-grain Item with normalized English content, taxonomy, attributes, signals, options, embedded normalized SKU data, review aggregates, and lineage back to the source Capture. After normalization closes, Enrich publishes the complete committed Item scope into the connected Product, Variant, Listing, Offer, Review, Store, and Change model. This final preparation is included and consumes no additional credits. See [Enriching Captures](/docs/guides/enriching-captures). ## Product, Variant, Listing, Offer, Review, and Store Enrich publishes the analytical model: * a **Product** is a normalized product family; * a **Variant** is an exact canonical configuration under a Product; * a **Listing** is a store-specific source SKU linked to a Variant; * an **Offer** is an observed price, availability, seller, and stock fact for a Listing; * a **Review** is an observed normalized review aggregate for a Listing and Store; * a **Store** is an organization-scoped host and country pair. Matching quality depends on the identifiers and product evidence present in the source data. See [Data model](/docs/data) for grains, lineage, and relationships. ## How they relate | Step | What happens | | -------------------------- | -------------------------------------------------------------------------------------------- | | 1. **You provide** | A URL and country | | 2. **Robot** | Track generation and validation until the stable Robot is ready | | 3. **Schedule** (optional) | Automate recurring extractions on a cadence | | 4. **Run** | The robot crawls start URLs and extracts products (manual or via schedule) | | 5. **Import** (optional) | Upload catalog data you already have | | 6. **Captures** | Page or catalog records produced by Runs or Imports | | 7. **Enrichment** | Produces one Item per successful Capture, then publishes the committed analytical projection | | 8. **Items** | One normalized page-grain record per successful Capture | | 9. **Explore** | Provides evidence views, Analyses, custom Query, and Agent access | --- ## Introduction Learn how Extralt extracts public ecommerce pages into Captures, enriches them into Items, and connects product data across stores. URL: https://extralt.com/docs/introduction **Beyond ecommerce scraping. Extract, enrich, and compare product data across stores.** Give Extralt a public product or catalog URL and a country. Extract uses compiled extraction logic built for the website to create structured Captures with the original URL and observation time. Enrich turns each successful Capture into one normalized Item, then connects Products, exact Variants, store Listings, observed Offers, Reviews, and Stores before the Enrichment becomes ready. Explore provides evidence views, four repeatable Analyses, custom questions across the connected model, and the same capabilities through the dashboard Agent. ## Who is Extralt for? Extralt is for technical teams that need reusable ecommerce product data from public sources without building and maintaining a custom scraper for every website: * **Price intelligence** -- monitor competitor pricing across the open web * **Catalog enrichment** -- fill gaps in your product data with external sources * **Assortment analysis** -- compare observed catalogs and exact matched Variants * **Product research** -- reuse source evidence, taxonomy, identifiers, and history ## What can you do with it? Extralt's pipeline has three stages. | Stage | What it does | Status | | ----------- | ---------------------------------------------------------------------------------------- | --------- | | **Extract** | Run managed ecommerce extraction and produce Captures | Available | | **Enrich** | Produce one normalized Item per successful Capture and publish its analytical projection | Available | | **Explore** | Browse evidence, run four Analyses, and ask custom questions across the connected model | Available | The pipeline is useful incrementally. Captures can be inspected and exported without Enrich. Items can be queried directly, while an Enrichment remains active until its committed scope is ready for Explore. ## How it works Extralt uses an LLM-based harness to design extraction logic for a website, then compiles and validates that logic before it is used for repeated Runs. Extraction itself runs as compiled code rather than sending every product page to an LLM. You provide a URL and a country. Extralt either reuses a compatible Robot or creates a Robot and starts its internal build. Once it is completed, create a Run manually, create a recurring Schedule, or ask the dashboard Agent to prepare an approval plan. The Agent can prepare a Robot, Run, Schedule, or Enrichment operation, but it never executes state-changing work without dashboard approval. --- ## Quickstart Extract your first ecommerce product data by creating a Robot, running product URLs, and inspecting structured Captures. URL: https://extralt.com/docs/introduction/quickstart This guide walks through one complete extraction: create a Robot, wait for it to become runnable, start a Run, and inspect the resulting Captures. Every step includes the dashboard workflow and its API equivalent. ## Prerequisites 1. Create an account at [extralt.com](https://extralt.com) 2. Create an organization 3. Subscribe to a plan (Start includes a 7-day free trial with 5,000 credits) 4. Generate an API key from the dashboard (needed for API usage) See [Account Setup](/docs/guides/account-setup) for detailed instructions. ## Create a Robot A Robot is the stable extraction resource for one host and country. Extralt builds and validates its internal crawler and scraper, then reuses the same Robot for later Runs. **• Dashboard:** go to **Extract > Robots > New**, enter a product URL from the target site, select a country, and choose **Create**. The dashboard opens the details page for the returned Robot so you can monitor its status. {/* Screenshot placeholder: Quickstart Robot creation form with a valid product URL and country selected. Show the current List, New, and Details tabs. */} **• API:** cURL Python Node.js ```bash export EXTRALT_API_KEY="your-api-key" curl -s -X POST "https://api.extralt.com/v1/extract/robots" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: quickstart-robot-1" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example-store.com/products/sample", "country_code": "US" }' | jq ``` ```python import requests API_KEY = "your-api-key" HEADERS = {"Authorization": f"Bearer {API_KEY}"} response = requests.post( "https://api.extralt.com/v1/extract/robots", headers={**HEADERS, "Idempotency-Key": "quickstart-robot-1"}, json={ "url": "https://example-store.com/products/sample", "country_code": "US", }, ) response.raise_for_status() robot = response.json() print(f"Robot ID: {robot['id']}") ``` ```javascript const API_KEY = "your-api-key"; const headers = { Authorization: `Bearer ${API_KEY}` }; const response = await fetch("https://api.extralt.com/v1/extract/robots", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "quickstart-robot-1", }, body: JSON.stringify({ url: "https://example-store.com/products/sample", country_code: "US", }), }); if (!response.ok) throw new Error(await response.text()); const robot = await response.json(); console.log(`Robot ID: ${robot.id}`); ``` The response contains the stable Robot ID and its status. `202 Accepted` means the Robot was created and its build was queued. `200 OK` means that Robot already existed. In both cases, `id` identifies the same Robot lifecycle. For the following cURL examples, copy that ID into an environment variable: ```bash export ROBOT_ID="" ``` For a compatible covered source, the response can return an existing Robot immediately. Otherwise, Extralt analyzes the source, generates extraction logic, validates it, and compiles it. Build time varies with the source and validation work required. ## Wait for the Robot **• Dashboard:** after creation, the Robot details page shows its live status. When the status is `completed`, the Robot becomes available in Run and Schedule selectors. {/* Screenshot placeholder: Quickstart Robot details page for nike_com_US with status Building and the stable Robot ID in the URL. */} **• API:** poll the Robot until it completes. cURL Python Node.js ```bash curl -s "https://api.extralt.com/v1/extract/robots/$ROBOT_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq '.status' ``` ```python import time while True: response = requests.get( f"https://api.extralt.com/v1/extract/robots/{robot['id']}", headers=HEADERS ) data = response.json() status = data["status"] print(f"Status: {status}") if status == "completed": robot_id = data["id"] break if status == "failed": raise RuntimeError(data.get("status_reason", "Robot build failed")) time.sleep(10) ``` ```javascript let robotId; while (true) { await new Promise((r) => setTimeout(r, 10000)); const res = await fetch(`https://api.extralt.com/v1/extract/robots/${robot.id}`, { headers, }); const data = await res.json(); console.log(`Status: ${data.status}`); if (data.status === "completed") { robotId = data.id; break; } if (data.status === "failed") { throw new Error(data.status_reason ?? "Robot build failed"); } } ``` The ID does not change while the Robot builds. Use it to start Runs once the status is `completed`. ## Start a Run A Run uses a completed Robot to crawl pages and produce Captures. **• Dashboard:** select **Start Run** on a completed Robot, or go to **Extract > Runs > New**. The selector shows only completed Robots. Enter optional start URLs and a crawl budget, then choose **Start**. The dashboard opens the new Run's details page. {/* Screenshot placeholder: Quickstart New Run form with nike_com_US selected. Show the start URL, crawl budget, and auto-enrich controls. */} **• API:** cURL Python Node.js ```bash curl -s -X POST "https://api.extralt.com/v1/extract/runs" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: quickstart-run-1" \ -H "Content-Type: application/json" \ -d '{ "robot_id": "'$ROBOT_ID'", "start_urls": ["https://example-store.com/products/sample"], "budget": 10 }' | jq ``` ```python response = requests.post( "https://api.extralt.com/v1/extract/runs", headers={**HEADERS, "Idempotency-Key": "quickstart-run-1"}, json={ "robot_id": robot_id, "start_urls": ["https://example-store.com/products/sample"], "budget": 10, }, ) response.raise_for_status() run = response.json() print(f"Run ID: {run['id']}") ``` ```javascript const runResponse = await fetch("https://api.extralt.com/v1/extract/runs", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "quickstart-run-1", }, body: JSON.stringify({ robot_id: robotId, start_urls: ["https://example-store.com/products/sample"], budget: 10, }), }); if (!runResponse.ok) throw new Error(await runResponse.text()); const run = await runResponse.json(); console.log(`Run ID: ${run.id}`); ``` The response is `202 Accepted` with `{ "id": "" }`. The Run receives the next name in the Robot's sequence, such as `nike_com_US_1`. For the following cURL examples, copy the returned Run ID as well: ```bash export RUN_ID="" ``` ## View your captures Once the run completes, your extracted data is ready. **• Dashboard:** go to **Extract > Captures**, select your run from the filter, and browse the results. Click any row to see the full extraction data. You can export to JSONL or Parquet using the download button. **• API:** cURL Python Node.js ```bash curl -s "https://api.extralt.com/v1/extract/captures?run_id=$RUN_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` ```python # Poll until the run completes while True: response = requests.get(f"https://api.extralt.com/v1/extract/runs/{run['id']}", headers=HEADERS) status = response.json()["status"] if status in ("completed", "failed", "stopped"): break time.sleep(10) # Fetch captures response = requests.get( "https://api.extralt.com/v1/extract/captures", headers=HEADERS, params={"run_id": run["id"]}, ) data = response.json() for capture in data["data"]: print(f"Title: {capture['title']}") print(f"Brand: {capture['brand']}") ``` ```javascript // Poll until the run completes let runStatus; do { await new Promise((r) => setTimeout(r, 10000)); const res = await fetch(`https://api.extralt.com/v1/extract/runs/${run.id}`, { headers }); const data = await res.json(); runStatus = data.status; } while (!["completed", "failed", "stopped"].includes(runStatus)); // Fetch captures const capturesRes = await fetch( `https://api.extralt.com/v1/extract/captures?run_id=${run.id}`, { headers }, ); const data = await capturesRes.json(); data.data.forEach((capture) => { console.log(`Title: ${capture.title}`); console.log(`Brand: ${capture.brand}`); }); ``` Want to automate recurring extractions? Check out [Schedules](/docs/guides/schedules) to run extractions on a cadence. For the complete Robot and Run lifecycle, see [Extracting data](/docs/guides/extracting-data). ## Continue through the pipeline After the Run completes, you can: * start an [Enrichment](/docs/guides/enriching-captures) to create normalized Items; * inspect the [data model](/docs/data) and its source lineage; * use [Explore](/docs/guides/exploring-data) once Enrich has published relationships; * ask the [dashboard Agent](/docs/guides/using-the-agent) to inspect operations, run an Analysis, ask a custom product-data question, or prepare the next operation for approval. --- ## Glossary Definitions for Extralt product, API, ecommerce extraction, enrichment, product matching, pricing, and market intelligence terms used in the docs. URL: https://extralt.com/docs/reference/glossary ## Analysis An Explore calculation with explicit inputs, eligibility, metrics, coverage, freshness, limitations, and evidence. Extralt currently provides Price position, Price movements, Availability changes, and exact-Variant Assortment overlap as packaged Analyses. ## Capture A raw extraction output produced by Extract from a source URL. Captures preserve source-page product data in the original language, including images, options, SKUs, offers, identifiers, and capture-time aggregates such as price range and availability. See [Working with Captures](/docs/guides/working-with-captures). ## Credit The shared unit of usage billing in Extralt. Credits are consumed by product-specific build actions: Extract uses 2 credits per successful product-page Capture, and Enrich uses 1 credit per Capture. The dashboard Agent and supported AI-assisted dashboard queries are included with an active subscription and do not consume credits. See [Credits & Billing](/docs/guides/credits-billing). ## Item The page-grain output produced by Enrich from one Capture. Items carry normalized English product content, taxonomy, attributes, signals, option and size interpretation, selected media, identifiers, embedded normalized SKU commerce data, normalized review state, and lineage. Items are the durable normalization output and the input to Enrich's connected analytical model. ## Listing A store-specific source SKU identity produced by Enrich from Items. A Listing links a source URL, Store, identifiers, media, and observation lifecycle to one inferred Variant. The same Variant can appear as many Listings across Stores. See the [Product Taxonomy Explorer](/tools/taxonomy-explorer) for the category and attribute structure used during enrichment. ## Offer An append-only seller, price, availability, and stock observation attached to a Listing. Offers include price, compare-at price, currency, condition, availability, seller identity and type, and categorical stock level. Variant context is reached through the Listing. Current state is the complete set of Offers for a Listing at its latest Extract `run_started_at`, not an arbitrary latest row. ## Organization The top-level scope for all Extralt resources. Robots, schedules, runs, captures, credits, and API keys belong to an organization. Each org has its own subscription. Users can belong to multiple organizations. See [Account Setup](/docs/guides/account-setup). ## Product A canonical product family published by Enrich that groups sibling Variants. For example, multiple exact color and size configurations can be separate Variants under one Product. Products contain canonical content and taxonomy selected from Item evidence. ## Query A persisted dashboard result for one custom data question. Extralt loads the relevant Capture, Item, or connected Explore model, generates a bounded read query, and retains the question, SQL, rows, status, and truncation state. Query is exploratory and does not replace a packaged Analysis when its contract applies. ## Review An append-only review aggregate observation attached to a Listing and Store. Reviews store compact normalized evidence: review count plus score on a 0-100 scale. Current Review views select the latest known observation for each active Listing. Variant and Product context is reached through the Listing. Raw average and scale remain on Captures for audit. ## Robot A stable extraction resource for a specific host and country. Its status tracks creation of the internal crawler and scraper, and its ID remains the same from build through every Run. Completed Robots are reusable across multiple Runs. See [Extracting data](/docs/guides/extracting-data). ## Run An extraction job that uses a robot to crawl start URLs and produce captures. Runs have a lifecycle (pending, running, completed, failed, stopped) and optionally a budget to limit credit usage. Runs can be created manually or by a schedule. See [Extracting data](/docs/guides/extracting-data). ## Schedule A recurring extraction automation. Links a robot to a cadence (e.g. every hour, every day, every week) and automatically creates runs on that schedule. Schedules can be paused and resumed, and auto-pause when credits run out. See [Schedules](/docs/guides/schedules). ## SKU A purchasable configuration extracted from one website. A SKU is the concrete option a customer can buy there: it has identifiers, stock, and one or more Offers. SKUs belong to the website's catalog and are not used as cross-store product identity. ## Store An organization-scoped host and country pair in the analytical model. Stores provide market and source context for Items, Listings, Offers, and Reviews. A Store is not a Robot, retailer group, or legal company. ## Change An append-only record of an observed semantic change. A Change names the entity, aspect, and action, retains the Run and observation time, and stores the before and after state as JSON evidence. ## Enrichment A processing job that reads Captures, writes one Item for each successfully processed Capture, then publishes the exact committed scope for Explore. Enrichments can be created, inspected, and stopped through the dashboard or public API. Stop prevents new credit spend while committed work finishes final preparation. ## Variant A canonical identity for one exact product configuration across stores. Variants are created by Enrich, can have many Listings, and are the cross-store matching unit used for price and availability comparison. Matching depends on the identifiers and product evidence available in the source data. --- ## Authentication Authenticate API requests with org-scoped Extralt API keys, Bearer tokens, rotation guidance, and safe handling for production integrations. URL: https://extralt.com/docs/using-the-api/authentication Public API requests require authentication via an **org-scoped API key**. Each key grants access to the supported Extract, Enrich, and Explore resources for one organization. Requests without a valid key receive a `401 Unauthorized` response. Compatible agent clients use OAuth through the separate MCP endpoint rather than an API key. See [Connect through MCP](/docs/guides/using-mcp). ## Getting your API key 1. Sign in to the [Extralt dashboard](https://extralt.com) 2. Select your organization 3. Navigate to API key settings 4. Create a new API key API keys are **org-scoped**. Each key is tied to a specific organization. If you have multiple organizations, generate a separate key for each. ## Using your API key Include your API key in the `Authorization` header as a Bearer token: ``` Authorization: Bearer your-api-key ``` ## Example request cURL Python Node.js ```bash curl "https://api.extralt.com/v1/extract/robots" \ -H "Authorization: Bearer your-api-key" ``` ```python response = requests.get( "https://api.extralt.com/v1/extract/robots", headers={"Authorization": "Bearer your-api-key"}, ) print(response.json()) ``` ```javascript const response = await fetch("https://api.extralt.com/v1/extract/robots", { headers: { Authorization: "Bearer your-api-key" }, }); const robots = await response.json(); console.log(robots); ``` ## Base URL All API requests use the host `https://api.extralt.com` with a versioned, pipeline-scoped prefix: ``` https://api.extralt.com/v1/extract/... # Extract pipeline (robots, runs, captures, schedules, imports) https://api.extralt.com/v1/enrich/... # Enrich pipeline (enrichments, items) https://api.extralt.com/v1/explore/... # Explore evidence and four Analyses ``` ## Security Treat your API key like a password. Do not commit it to version control or expose it in client-side code. * Store keys in environment variables or a secrets manager * Rotate keys periodically * Revoke compromised keys immediately from the dashboard * Each key is scoped to one organization and cannot access other orgs' data ## Error responses If authentication fails, the API returns a `401 Unauthorized` response: ```json { "error": { "code": "unauthorized", "message": "A valid Bearer credential is required", "request_id": "019..." } } ``` See the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) for endpoint-specific response schemas. ## Next steps * [Making Requests](/docs/using-the-api/making-requests) — request and response conventions * [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) — authoritative endpoints and schemas * [Common Patterns](/docs/using-the-api/common-patterns) — pagination, filtering, and polling * [Connect through MCP](/docs/guides/using-mcp) — OAuth setup for compatible agent clients --- ## Common patterns Poll asynchronous work, handle errors, paginate results, respect backpressure, and export Captures safely. URL: https://extralt.com/docs/using-the-api/common-patterns The examples below use the Extract base URL. Use the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) for route-specific statuses and schemas. ## Polling a Run Runs are asynchronous. After creating a Run, poll until it reaches a terminal state such as `completed`, `failed`, or `stopped`. Python Node.js ```python import time import requests def wait_for_run(run_id, *, timeout_seconds=3600): deadline = time.monotonic() + timeout_seconds while time.monotonic() < deadline: response = requests.get( f"https://api.extralt.com/v1/extract/runs/{run_id}", headers=HEADERS, ) response.raise_for_status() run = response.json() if run["status"] in ("completed", "failed", "stopped"): return run time.sleep(10) raise TimeoutError(f"Run {run_id} did not finish before the client timeout") ``` ```javascript async function waitForRun(runId, timeoutMs = 3_600_000) { const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { const response = await fetch( `https://api.extralt.com/v1/extract/runs/${runId}`, { headers }, ); if (!response.ok) throw new Error(`Extralt request failed: ${response.status}`); const run = await response.json(); if (["completed", "failed", "stopped"].includes(run.status)) return run; await new Promise((resolve) => setTimeout(resolve, 10_000)); } throw new Error(`Run ${runId} did not finish before the client timeout`); } ``` Use a client-side timeout and a bounded polling interval. Completion time depends on source coverage, crawl scope, and queue state. ## Handling errors Check the status before decoding a success payload. API errors use the stable `{ "error": { "code", "message", "request_id" } }` envelope; retain the request ID when contacting support. ```python response = requests.post( url, headers={**HEADERS, "Idempotency-Key": idempotency_key}, json=payload, ) if response.status_code == 429: # Apply bounded backoff, then retry only if the operation is safe to repeat. pass elif response.status_code >= 400: raise RuntimeError( f"Extralt request failed ({response.status_code}): {response.text}" ) result = response.json() ``` For create and restart requests, retry the same payload with the original `Idempotency-Key`. This returns the original result instead of duplicating work. A key reused with a different payload returns `409 Conflict`. ## Pagination List responses use cursor pagination. Pass a non-null `next_cursor` as the `cursor` query parameter for the next page. ```python def get_all_captures(run_id): rows = [] cursor = None while True: params = {"run_id": run_id} if cursor is not None: params["cursor"] = cursor response = requests.get( "https://api.extralt.com/v1/extract/captures", headers=HEADERS, params=params, ) response.raise_for_status() page = response.json() rows.extend(page["data"]) cursor = page["next_cursor"] if cursor is None: return rows ``` Treat cursors as opaque. Do not decode, construct, or replace one with a resource id. Preserve the same endpoint, filters, and sort across pages; the next request may choose a different valid `limit`. Pagination reads live data rather than holding a database transaction across HTTP requests. On unchanged data, keyset cursors traverse deterministically. Rows written between requests can affect the remaining pages, so restart without a cursor when you need a refreshed traversal. ## Explore Analysis pages Pageable Explore Analysis responses use `rows` rather than `data`. Their summary, coverage, and freshness describe the complete selected Analysis scope, while `rows` contains only the current evidence page. On unchanged data, those scope-level values repeat on later pages. A non-null `next_cursor` is the only continuation signal. ## Rate-limit handling A `429` response is authoritative. Honor `Retry-After` when present, then retry with exponential backoff, random jitter, and a maximum attempt count. Do not build against an observed request rate as if it were a permanent quota; operational limits can change. Reads are generally safe to retry. Retry a mutation only with the same `Idempotency-Key` and payload, or when the operation is otherwise documented as idempotent. ## Bulk Capture export Use the Capture export route instead of paginating when you need all Captures from one Run or Import as JSONL or Parquet. Stream the response to disk rather than loading the entire file in memory. See [Working with Captures](/docs/guides/working-with-captures#exporting-captures). --- ## Making requests Apply Extralt API request conventions for authentication, JSON payloads, asynchronous work, filtering, and pagination. URL: https://extralt.com/docs/using-the-api/making-requests Use the generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) to select a route and inspect its authoritative request and response schema. This page documents conventions that apply across API groups. ## Setup cURL Python Node.js ```bash export EXTRALT_API_KEY="your-api-key" export EXTRALT_EXTRACT_URL="https://api.extralt.com/v1/extract" ``` ```python import requests API_KEY = "your-api-key" EXTRACT_URL = "https://api.extralt.com/v1/extract" HEADERS = {"Authorization": f"Bearer {API_KEY}"} ``` ```javascript const API_KEY = "your-api-key"; const EXTRACT_URL = "https://api.extralt.com/v1/extract"; const headers = { Authorization: `Bearer ${API_KEY}` }; ``` ## JSON requests Send JSON request bodies with `Content-Type: application/json`. Request fields use `snake_case`. cURL Python Node.js ```bash curl -s -X POST "$EXTRALT_EXTRACT_URL/robots" \ -H "Authorization: Bearer $EXTRALT_API_KEY" \ -H "Idempotency-Key: robot-create-example-1" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example-store.com/products/sample", "country_code": "US" }' | jq ``` ```python response = requests.post( f"{EXTRACT_URL}/robots", headers={**HEADERS, "Idempotency-Key": "robot-create-example-1"}, json={ "url": "https://example-store.com/products/sample", "country_code": "US", }, ) response.raise_for_status() robot = response.json() ``` ```javascript const response = await fetch(`${EXTRACT_URL}/robots`, { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "robot-create-example-1", }, body: JSON.stringify({ url: "https://example-store.com/products/sample", country_code: "US", }), }); if (!response.ok) throw new Error(`Extralt request failed: ${response.status}`); const robot = await response.json(); ``` Do not infer response casing or optionality from a request example. Generate types from OpenAPI or validate responses against its schemas. ## Idempotent mutations Robot, Run, Schedule, Import, and Enrichment creation, plus Run restart, require an `Idempotency-Key` header. Use a unique, stable key for one logical operation. If the connection fails, retry the same payload with the same key. Reusing that key with a different payload returns `409 Conflict`. Keys contain 1 to 255 visible ASCII characters. Do not recycle keys across unrelated operations. ## Asynchronous work Robots, Runs, Imports, and Enrichments can be asynchronous. A create request returns the resource or job identifier; read the corresponding resource until it reaches a terminal state. Keep the identifier as lineage for later Captures or Items. Use bounded polling with a delay. Do not poll continuously or assume a fixed completion time. See [Common patterns](/docs/using-the-api/common-patterns#polling-a-run) for an example. ## Lists and filters List routes accept resource-specific filters. For example, Captures can be scoped to a Run, Robot, or Import. Prefer the narrowest server-side filter available instead of downloading an organization-wide result and filtering it locally. ```bash curl -s "$EXTRALT_EXTRACT_URL/captures?run_id=$RUN_ID" \ -H "Authorization: Bearer $EXTRALT_API_KEY" | jq ``` Use cursor pagination when `next_cursor` is non-null. Treat the cursor as opaque and keep the endpoint, filters, and sort unchanged. See [Pagination](/docs/using-the-api/common-patterns#pagination). ## Errors Check the HTTP status before reading a success payload. Treat `401` and `403` as authentication or organization-scope failures, `4xx` validation errors as request problems, `429` as backpressure, and `5xx` as retryable only when the operation is safe to retry. For mutations, retain the original `Idempotency-Key`. See [Error handling](/docs/using-the-api/common-patterns#handling-errors). --- ## Error Codes Stable Extralt API error envelope, machine-readable codes, request IDs, and retry guidance. URL: https://extralt.com/docs/api/error-codes The Extralt API returns standard HTTP statuses and one stable JSON error envelope: ```json { "error": { "code": "invalid_request", "message": "robot_id is required", "request_id": "019..." } } ``` `error.code` is machine-readable. `error.message` is safe to show to a user. `error.request_id` matches the `x-request-id` response header and should be included when contacting support. ## Codes | HTTP | `error.code` | Meaning | | ----- | ------------------------ | ------------------------------------------------------------------------------------------------- | | `400` | `invalid_request` | The request syntax, query parameters, path values, or domain input is invalid | | `401` | `unauthorized` | The Bearer credential is missing or invalid | | `402` | `payment_required` | The organization needs a subscription or credits | | `403` | `forbidden` | The credential or organization cannot access this operation | | `404` | `not_found` | The route or organization-scoped resource does not exist | | `405` | `method_not_allowed` | The route does not support that HTTP method | | `409` | `conflict` | The operation conflicts with resource state or an idempotency key was reused with another payload | | `413` | `payload_too_large` | The request body exceeds the API size limit | | `415` | `unsupported_media_type` | A JSON route did not receive `application/json` | | `422` | `unprocessable_entity` | JSON was parsed but could not be decoded into the requested schema | | `429` | `rate_limit_exceeded` | The request exceeded an operational rate limit | | `500` | `internal_error` | An unexpected server error occurred; internal details are not exposed | | `503` | `upstream_unavailable` | A required upstream service is temporarily unavailable | | `504` | `request_timeout` | The request exceeded its server-side time budget | A `401` also includes `WWW-Authenticate`. A `429` includes `Retry-After` when the server can calculate the delay. ## Handling errors ```python response = requests.post( "https://api.extralt.com/v1/extract/runs", headers={**HEADERS, "Idempotency-Key": "run-create-019..."}, json={"robot_id": robot_id, "start_urls": [url]}, ) if response.status_code >= 400: error = response.json()["error"] print(f"{error['code']}: {error['message']} ({error['request_id']})") ``` ```javascript const response = await fetch("https://api.extralt.com/v1/extract/runs", { method: "POST", headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": "run-create-019...", }, body: JSON.stringify({ robot_id: robotId, start_urls: [url] }), }); if (!response.ok) { const { error } = await response.json(); console.error(`${error.code}: ${error.message} (${error.request_id})`); } ``` Retry reads after bounded backoff when appropriate. Retry create or restart operations only with the same payload and original `Idempotency-Key`; changing the payload requires a new key. --- ## API Reference Stable Extralt API v1 routes for extraction, imports, enrichment, items, and Explore evidence and analysis views. URL: https://extralt.com/docs/api The stable Extralt REST API is available at **[api.extralt.com](https://api.extralt.com)**. Public v1 requests require an org-scoped API key passed as a Bearer token: `Authorization: Bearer `. An active subscription is required for writes. After a subscription ends, the 30-day grace period permits read-only API access and exports. After grace, organization access is suspended; after 180 days, the organization is deactivated. Billing and reactivation remain available through the dashboard while an organization is suspended. During grace, stop and pause operations remain available to reduce risk. Retrying a completed idempotent request returns its stored result, while a new request is rejected with `402 Payment Required`. Suspended and deactivated organizations cannot use these data operations. The generated [OpenAPI document](https://api.extralt.com/api-docs/openapi.json) is the authoritative reference for request fields, response schemas, status codes, and enums. [api.extralt.com/docs](https://api.extralt.com/docs) provides stable links to that document and these developer guides. For compatible agent clients, Extralt exposes the same customer-facing capabilities as task-oriented MCP tools with OAuth. MCP is documented separately because its tools are not REST routes. See [Connect through MCP](/docs/guides/using-mcp). ## Getting Started 1. [Create an account](/sign-up) and subscribe to a plan 2. Generate an API key from your dashboard 3. Start making requests under `https://api.extralt.com/v1` Create and restart operations require an `Idempotency-Key` header so that a network retry cannot duplicate work. ## Endpoints --- ## Rate Limits Handle Extralt API backpressure with Retry-After, bounded exponential backoff, jitter, and idempotent mutation retries. URL: https://extralt.com/docs/api/rate-limits The Extralt API applies token-bucket rate limiting per organization and a separate protective budget before external API-key verification. Operational limits may vary by environment or plan and are not part of the versioned API schema. A `429 Too Many Requests` response is always authoritative. ## Rate-limit response ```json { "error": { "code": "rate_limit_exceeded", "message": "Too many requests; retry after the delay in the Retry-After header", "request_id": "019..." } } ``` When present, `Retry-After` is a number of seconds. Wait at least that long. Otherwise, use exponential backoff with random jitter and a bounded attempt count. ```python import random import time def request_with_backoff(method, url, *, max_attempts=4, **kwargs): for attempt in range(max_attempts): response = requests.request(method, url, **kwargs) if response.status_code != 429: return response retry_after = response.headers.get("Retry-After") base_delay = float(retry_after) if retry_after else 2 ** attempt time.sleep(base_delay + random.uniform(0, 0.5)) return response ``` ```javascript async function requestWithBackoff(url, options = {}, maxAttempts = 4) { let response; for (let attempt = 0; attempt < maxAttempts; attempt++) { response = await fetch(url, options); if (response.status !== 429) return response; const retryAfter = Number(response.headers.get("Retry-After")); const baseDelayMs = Number.isFinite(retryAfter) ? retryAfter * 1000 : 1000 * 2 ** attempt; const jitterMs = Math.random() * 500; await new Promise((resolve) => setTimeout(resolve, baseDelayMs + jitterMs)); } return response; } ``` Reads are generally safe to retry. For create and restart operations, reuse the same request payload and `Idempotency-Key`; do not generate a new key for each retry. Keep polling intervals bounded and use Capture export instead of rapid pagination when downloading a complete Run or Import. --- ## Bright Data alternative for ecommerce product data - Extralt Compare Extralt and Bright Data for ecommerce product data, web scraping, price monitoring, enrichment, matching, and owned product intelligence. URL: https://extralt.com/compare/bright-data Choose Bright Data when you need broad proxy, browser, and dataset infrastructure. Choose Extralt when the job is ecommerce web scraping and the output needs to become normalized product intelligence instead of another raw data feed. Best fit for Bright Data: Teams that need proxy infrastructure across many non-ecommerce use cases.; Enterprises buying broad datasets across categories outside retail.; Scraping teams that already own their normalization and product matching layers. Best fit for Extralt: Ecommerce teams building price monitoring, catalog enrichment, or market intelligence.; Developers who need product records, not raw HTML or page-level text.; Agent and analytics teams that need product identity, seller evidence, and freshness metadata. Last reviewed: 2026-06-15 --- ## Apify alternative for ecommerce scraping - Extralt Compare Extralt and Apify for ecommerce scraping, crawler maintenance, SKU-level product data, price monitoring, and owned ecommerce records. URL: https://extralt.com/compare/apify Choose Apify when you want a broad actor marketplace or to run your own scraping code. Choose Extralt when your target is ecommerce data and you want a maintained product schema, SKU-level extraction, enrichment, and matching. Best fit for Apify: Developers who want a broad scraping and automation platform.; Teams with custom workflows outside ecommerce.; Projects where a marketplace Actor already solves the exact target site. Best fit for Extralt: Teams tracking ecommerce pages across many retailers.; Price monitoring and product data pipelines that need stable SKU-level output.; Buyers who do not want to own scraper maintenance or product normalization. Last reviewed: 2026-06-15 --- ## Firecrawl alternative for ecommerce extraction - Extralt Compare Extralt and Firecrawl for AI web scraping, ecommerce product extraction, SKU-level product records, and structured product intelligence. URL: https://extralt.com/compare/firecrawl Choose Firecrawl when your app needs clean markdown, HTML, screenshots, or a one-off JSON extraction from known URLs. Choose Extralt when the source is ecommerce and the extraction needs to produce product data from the start. Best fit for Firecrawl: AI apps that need clean markdown or page content from arbitrary websites.; Agents that need search, crawl, map, and browser-like web actions.; Developers building RAG or research workflows outside ecommerce. Best fit for Extralt: Ecommerce data teams extracting product pages on a schedule.; Price, assortment, and product intelligence workflows where SKU-level records matter.; Technical teams building product-data APIs or custom price-comparison workflows. Last reviewed: 2026-06-15 --- ## DataWeave competitor for ecommerce intelligence - Extralt Compare Extralt and DataWeave for ecommerce analytics, pricing intelligence, assortment analytics, product matching, and data ownership. URL: https://extralt.com/compare/dataweave Choose DataWeave when you want an analytics product and managed retail intelligence workflows. Choose Extralt when you want enriched product data to power your own analytics, APIs, and applications. Best fit for DataWeave: Retailers and brands that want a managed analytics platform.; Teams that prefer vendor-led reporting over building internal data workflows.; Business users who need pricing, assortment, and digital shelf dashboards. Best fit for Extralt: Data and product teams that want API-first ecommerce intelligence.; Teams bringing their own warehouse, notebooks, SQL, Hex, or custom apps.; Technical teams that need the product records behind the dashboard. Last reviewed: 2026-05-10 --- ## Prisync alternative for competitor price data - Extralt Compare Extralt and Prisync for competitor price monitoring, dynamic pricing, below-MAP checks, exports, and owned ecommerce pricing data. URL: https://extralt.com/compare/prisync Choose Prisync when you want a pricing dashboard and rule-based dynamic pricing. Choose Extralt when price monitoring is one workflow on top of ecommerce data you own. Best fit for Prisync: Merchants that want a ready-made competitor pricing dashboard.; Teams that need dynamic pricing rules quickly.; Manufacturers that primarily need MAP monitoring reports. Best fit for Extralt: Teams that want to own the raw and enriched pricing data.; Companies combining price monitoring inputs with catalog enrichment and custom analysis.; Developers building internal tools, pricing models, or product-data APIs. Last reviewed: 2026-06-15 --- ## ScrapingBee alternative for ecommerce data - Extralt Compare Extralt and ScrapingBee for ecommerce web scraping, product extraction, pricing, proxies, and structured product intelligence. URL: https://extralt.com/compare/scrapingbee Choose ScrapingBee when you need a general scraping API with browser rendering, proxy options, and CSS or AI extraction rules. Choose Extralt when the source is ecommerce and web scraping needs to produce product records from the start. Best fit for ScrapingBee: Developers who need one scraping API across many non-ecommerce websites.; Teams that want to control CSS/XPath extraction rules themselves.; Projects where browser rendering and proxy configuration are the main problem. Best fit for Extralt: Ecommerce teams that need structured product records rather than page content.; Price monitoring and catalog enrichment workflows that need SKU, seller, and offer context.; Teams that want enrichment and cross-store relationships without building a second data project. Last reviewed: 2026-05-10 --- ## ScraperAPI alternative for ecommerce scraping - Extralt Compare Extralt and ScraperAPI for ecommerce scraping, structured data endpoints, product pages, price monitoring, and product intelligence. URL: https://extralt.com/compare/scraperapi Choose ScraperAPI when you need web access, geotargeting, JavaScript rendering, and structured endpoints for supported large sites. Choose Extralt when supported ecommerce sources need to follow one consistent product schema. Best fit for ScraperAPI: Teams that need a general web scraping API across many site types.; Developers scraping supported domains through prebuilt structured endpoints.; Projects where access and proxy management are the main bottleneck. Best fit for Extralt: Ecommerce teams that need product records across many retailers.; Price monitoring teams that need matched products, sellers, SKUs, and offer history.; Developers building ecommerce product-data APIs or internal tools. Last reviewed: 2026-05-10 --- ## Oxylabs alternative for ecommerce data - Extralt Compare Extralt and Oxylabs for ecommerce scraper APIs, product data extraction, pricing, proxy infrastructure, and product intelligence. URL: https://extralt.com/compare/oxylabs Choose Oxylabs when proxy depth, unblocking, and broad web collection infrastructure are central. Choose Extralt when ecommerce records, matching, enrichment, and owned product intelligence are the core requirement. Best fit for Oxylabs: Enterprises that need large-scale proxy and web data infrastructure.; Teams with existing product normalization and matching systems.; Projects spanning many non-ecommerce website categories. Best fit for Extralt: Ecommerce teams that want product records rather than collection infrastructure.; Price-monitoring and catalog teams that need observed history and cross-store matching.; Developers who want to build on a normalized ecommerce dataset. Last reviewed: 2026-05-10 --- ## Zyte alternative for ecommerce extraction - Extralt Compare Extralt and Zyte for ecommerce product extraction, automatic extraction, scraper infrastructure, pricing, and structured product data. URL: https://extralt.com/compare/zyte Choose Zyte when you need flexible scraping infrastructure, Scrapy-friendly workflows, and automatic extraction across ecommerce, articles, jobs, and SERP data. Choose Extralt when you only care about ecommerce product intelligence. Best fit for Zyte: Scrapy users and teams with broad web scraping requirements.; Projects spanning ecommerce, articles, jobs, forums, and SERP extraction.; Teams that want fine-grained control over scraping technology and extraction types. Best fit for Extralt: Teams that only need ecommerce product pages and price observations.; Product-data teams that want enrichment, observed history, and cross-store relationships on top of extraction.; Technical teams building custom price, availability, or assortment applications. Last reviewed: 2026-05-10 --- ## Scrapfly alternative for ecommerce data - Extralt Compare Extralt and Scrapfly for web scraping, ecommerce product extraction, AI extraction, pricing, and product intelligence workflows. URL: https://extralt.com/compare/scrapfly Choose Scrapfly when you need a broad developer platform for scraping, anti-bot handling, browser capture, screenshots, crawler jobs, and AI extraction. Choose Extralt when ecommerce extraction must produce normalized product records and observed history. Best fit for Scrapfly: Developers who want a broad web data platform across many site types.; Teams that need cloud browser, screenshots, crawler jobs, and extraction APIs together.; Projects where anti-bot handling and observability are the main buying criteria. Best fit for Extralt: Ecommerce data teams that need normalized product records.; Price and assortment teams that need observed history and product matching.; Technical teams building product-data applications rather than generic page extraction. Last reviewed: 2026-05-10 --- ## Competera competitor for ecommerce price data - Extralt Compare Extralt and Competera for competitive data, AI pricing, price monitoring, product matching, and ecommerce market intelligence. URL: https://extralt.com/compare/competera Choose Competera when you want an enterprise pricing platform with AI price recommendations and pricing experts. Choose Extralt when you want to own the observed ecommerce data that feeds pricing, below-MAP checks, market research, and analytics workflows. Best fit for Competera: Enterprise retailers buying a pricing optimization platform.; Teams that need AI price recommendations and what-if analysis.; Pricing organizations that want vendor-led implementation and pricing expertise. Best fit for Extralt: Teams that need the observed ecommerce data behind pricing decisions.; Analysts combining competitor prices, below-MAP checks, assortment data, and market research.; Data teams that want API-first product records before building models or dashboards. Last reviewed: 2026-05-10 --- ## Wiser alternative for retail price intelligence - Extralt Compare Extralt and Wiser for retail price intelligence, MAP workflows, digital shelf analytics, market intelligence, and owned ecommerce product data. URL: https://extralt.com/compare/wiser Choose Wiser when you want a mature retail intelligence application with dashboards, alerts, MAP workflows, and managed execution. Choose Extralt when you want public product observations for your own pricing and analysis workflows. Best fit for Wiser: Brands and retailers that want a mature retail intelligence suite.; Teams that need MAP enforcement workflows and business-user dashboards.; Organizations that also need in-store retail execution data. Best fit for Extralt: Data teams building their own price monitoring or below-MAP review system.; Analysts who need product-level evidence in SQL, BI, notebooks, or exports.; Ecommerce teams that want the same dataset to serve pricing, assortment, enrichment, and custom applications. Last reviewed: 2026-06-15 --- ## Price2Spy alternative for price monitoring - Extralt Compare Extralt and Price2Spy for price monitoring software, MAP workflows, repricing, product matching, exports, and ecommerce data ownership. URL: https://extralt.com/compare/price2spy Choose Price2Spy when you need a pricing dashboard, price alerts, marketplace monitoring, MAP monitoring, and repricing modules. Choose Extralt when price monitoring is one use case for an ecommerce dataset you own. Best fit for Price2Spy: Teams that need a price monitoring dashboard quickly.; Manufacturers tracking MAP violations with screenshot evidence.; Retailers that want repricing modules and ecommerce platform integrations. Best fit for Extralt: Teams that want pricing data plus broader product intelligence.; Data teams feeding pricing and below-MAP data into internal systems.; Ecommerce operators combining price monitoring with assortment and market research. Last reviewed: 2026-06-15 --- ## Profitero competitor for digital shelf data - Extralt Compare Extralt and Profitero for digital shelf analytics, ecommerce market research, MAP-related data, content checks, and product data ownership. URL: https://extralt.com/compare/profitero Choose Profitero when you want a brand-facing digital shelf analytics suite with services, retailer coverage, alerts, and integrations. Choose Extralt when you want to build ecommerce market research and analytics from open-web product data. Best fit for Profitero: Enterprise brands buying digital shelf analytics and services.; Teams that need retailer integrations, content workflows, and retail media activation.; Business users who want a finished platform rather than a data layer. Best fit for Extralt: Data teams building custom ecommerce market research and analytics.; Pricing and category teams that want product-level evidence in their own systems.; Technical teams building custom product-data and comparison applications. Last reviewed: 2026-05-10 --- ## CommerceIQ competitor for ecommerce analytics - Extralt Compare Extralt and CommerceIQ for ecommerce analytics, digital shelf optimization, retail media workflows, product data, and market intelligence. URL: https://extralt.com/compare/commerceiq Choose CommerceIQ when you want a unified ecommerce management platform across shelf, media, content, and retail operations. Choose Extralt when the main need is public product data for your own analytics and pricing systems. Best fit for CommerceIQ: Brands managing digital shelf, retail media, and content operations together.; Teams that need business-user workflows and automated executive reporting.; Organizations standardizing ecommerce operations inside one suite. Best fit for Extralt: Teams that need ecommerce product data in their own warehouse or API.; Analysts building custom market research, pricing, and assortment workflows.; Product teams building custom applications from public ecommerce observations. Last reviewed: 2026-05-10 --- ## Stackline competitor for ecommerce market data - Extralt Compare Extralt and Stackline for ecommerce market intelligence, price analytics, MAP-related data, shopper analytics, and product data ownership. URL: https://extralt.com/compare/stackline Choose Stackline when you want an upmarket analytics platform for ecommerce, shopper, pricing, and retail media decisions. Choose Extralt when you want public product observations for custom analysis in your own stack. Best fit for Stackline: Enterprise brands buying shopper and ecommerce market intelligence.; Teams that need surveys, panels, retail media context, and pricing analytics together.; Business users who want vendor-led research and dashboards. Best fit for Extralt: Teams building ecommerce market research from public product pages.; Analysts who need product-level price, seller, availability, and assortment evidence.; Builders who need a normalized ecommerce data API for custom tools. Last reviewed: 2026-05-10