{
  "title": "Shopify marketplace - choose apps or themes",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "mode": {
      "title": "Listing type",
      "type": "string",
      "description": "Choose the Shopify App Store (apps.shopify.com) or the Shopify Theme Store (themes.shopify.com). Both produce the same record shape, with a 'type' field of app or theme. Leave it alone to scrape apps.",
      "editor": "select",
      "enum": [
        "apps",
        "themes"
      ],
      "enumTitles": [
        "Apps - apps.shopify.com",
        "Themes - themes.shopify.com"
      ],
      "prefill": "apps",
      "sectionCaption": "1 · Listings to collect",
      "sectionDescription": "Choose apps or themes and the supported categories or collections."
    },
    "categories": {
      "title": "App categories or theme collections",
      "type": "array",
      "description": "App Store category slugs. Prefer a leaf (third-level) slug such as store-design-site-optimization-seo, marketing-and-conversion-marketing-email-marketing or orders-and-shipping-shipping-solutions-shipping: those have a paginated browse grid and can return hundreds of apps. A shorter parent slug like store-design-site-optimization also works, but Shopify publishes no browse grid for it, so it returns only the ~25-30 apps curated on that one page. The full list is at https://apps.shopify.com/sitemap_categories_en.xml. In themes mode these are Theme Store collection slugs - free-themes, trending-themes, new-themes, horizon-themes, large-inventory, small-inventory - or the word all for the whole /themes page. Pasting a full category URL works too. Leave empty to use a fast sample category.",
      "editor": "stringList",
      "prefill": [
        "store-design-site-optimization-seo"
      ]
    },
    "includeDetails": {
      "title": "Fetch app detail pages for developer information",
      "type": "boolean",
      "description": "App category cards carry everything except the developer name, so this adds one request per app to read it (plus developerUrl). apps.shopify.com throttles above about two requests a second, so 60 apps takes roughly 90-100 seconds instead of 2, and a few rows can still come back with a null developer if Shopify throttles hard - raise maxRunSeconds when you turn it on. Ignored in themes mode, where the detail page is always loaded because the developer, tagline and review count only exist there.",
      "editor": "checkbox",
      "default": false,
      "sectionCaption": "2 · Listing detail",
      "sectionDescription": "Detail-page requests can add information that listing pages omit."
    },
    "maxItems": {
      "title": "Maximum listings",
      "type": "integer",
      "description": "Stop after this many app or theme records in total, across every category selected. Each app costs one listing page request (20 apps per page) plus one detail page request, so a larger number needs a larger maxRunSeconds.",
      "editor": "number",
      "default": 60,
      "minimum": 1,
      "maximum": 5000,
      "sectionCaption": "3 · Run limits",
      "sectionDescription": "Start with a small listing cap and review the source response."
    },
    "maxRunSeconds": {
      "title": "Time budget (seconds)",
      "type": "integer",
      "description": "Hard wall-clock limit. The crawl stops cleanly when the budget runs out and keeps every record collected so far, so the run still succeeds. Raise it for large jobs. Listing-only runs are fast (60 app records in about 2 seconds); with developer lookups on, budget about one record per second.",
      "editor": "number",
      "default": 240,
      "minimum": 30,
      "maximum": 3600
    },
    "onlyNewSinceLastRun": {
      "title": "Only listings not seen in a previous run",
      "type": "boolean",
      "description": "Change detection. The actor remembers the handles it has already returned for this mode and category set, and skips them next time, so a scheduled run gives you only the new arrivals. The first run always returns everything. When nothing new has appeared the run finishes successfully with an empty dataset - that is the 'no changes' answer, not an error.",
      "editor": "checkbox",
      "default": false,
      "sectionCaption": "4 · Saved comparisons",
      "sectionDescription": "The first comparison establishes history. Reuse the same scope for later observations and avoid concurrent writers."
    },
    "stateStoreName": {
      "title": "Comparison history name",
      "type": "string",
      "editor": "textfield",
      "description": "Optional separate history for this workflow. Omit to keep the existing shared history. Use a unique name for QA or independent schedules and reuse it for subsequent comparisons. Use 3-63 letters, digits or hyphens; begin and end with a letter or digit.",
      "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]$",
      "sectionCaption": "Separate workflow history"
    }
  },
  "description": "Choose public app listings or theme collections, narrow the categories and set a small listing cap. Optional detail requests add only information exposed by the Store."
}
