{
  "id": "competitor-research-stack",
  "name": "Competitor Research Stack",
  "description": "Run a simple cross-platform competitor research sequence across Google Search, Google Ads Transparency, and Meta Ad Library.",
  "platform": "competitor-research-stack",
  "version": "1.0.0",
  "urlPatterns": [
    "*google.com/search*",
    "*adstransparency.google.com*",
    "*facebook.com/ads/library*"
  ],
  "tags": [
    "competitor-research",
    "meta",
    "google",
    "browser",
    "cdp"
  ],
  "successCount": 0,
  "failCount": 0,
  "flows": {
    "full_stack": {
      "steps": [
        "Discover category players on Google Search",
        "Validate active Google paid inventory with a domain lookup",
        "Validate active Meta campaign families with advertiser lookup"
      ],
      "guards": [
        "QUERY should be a market phrase",
        "DOMAIN should be the landing-page domain",
        "ADVERTISER should be the Meta page name"
      ],
      "why": "This sequence separates discovery from ad-library validation."
    }
  },
  "errors": [
    {
      "error": "none of the sources expose true conversion metrics",
      "context": "All three sources are outside-in validation tools",
      "solution": "Use repetition, longevity, and landing-page alignment as proxy signals.",
      "severity": "medium"
    }
  ],
  "steps": [
    {
      "action": "navigate",
      "url": "https://www.google.com/search?q={QUERY}",
      "description": "Open the discovery query on Google Search",
      "verify": "textarea#APjFqb",
      "verifyTimeoutMs": 15000
    },
    {
      "action": "wait",
      "ms": 1200,
      "description": "Wait for Google results"
    },
    {
      "action": "browser_js",
      "code": "(() => { const headings = [...document.querySelectorAll('h3')].map((el) => (el.textContent || '').trim()).filter(Boolean).slice(0, 8); return { query: `{QUERY}`, url: location.href, headings }; })()",
      "description": "Extract top Google competitor headings"
    },
    {
      "action": "navigate",
      "url": "https://adstransparency.google.com/?region=IN&domain={DOMAIN}",
      "description": "Open the Google Ads Transparency domain lookup",
      "verify": "input.input.input-area",
      "verifyTimeoutMs": 15000
    },
    {
      "action": "wait",
      "ms": 1500,
      "description": "Wait for Google Ads Transparency results"
    },
    {
      "action": "browser_js",
      "code": "(() => { const adCount = document.body.innerText.match(/\\b\\d+ ads\\b/i)?.[0] || null; const creativeLinks = [...document.querySelectorAll(\"a[href*='/advertiser/'][href*='/creative/']\")].map((el) => el.href).slice(0, 10); return { domain: `{DOMAIN}`, url: location.href, adCount, creativeLinks }; })()",
      "description": "Extract Google ad count and creative links"
    },
    {
      "action": "navigate",
      "url": "https://www.facebook.com/ads/library/?active_status=active&ad_type=all&country=IN&is_targeted_country=false&media_type=all&search_type=keyword_unordered&sort_data[direction]=desc&sort_data[mode]=total_impressions",
      "description": "Open Meta Ad Library in India all-ads mode",
      "verify": "input[placeholder='Search by keyword or advertiser']",
      "verifyTimeoutMs": 15000
    },
    {
      "action": "wait",
      "ms": 1500,
      "description": "Let Meta Ad Library settle"
    },
    {
      "action": "browser_js",
      "code": "(() => { const input = document.querySelector(\"input[placeholder='Search by keyword or advertiser']\"); if (!(input instanceof HTMLInputElement)) throw new Error('Meta Ad Library search input not found'); const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set; if (!setter) throw new Error('HTMLInputElement value setter unavailable'); setter.call(input, `{ADVERTISER}`); input.dispatchEvent(new Event('input', { bubbles: true })); input.dispatchEvent(new Event('change', { bubbles: true })); input.focus(); return { typed: input.value }; })()",
      "description": "Type the Meta advertiser page name"
    },
    {
      "action": "wait",
      "ms": 1500,
      "description": "Wait for Meta advertiser suggestions"
    },
    {
      "action": "browser_js",
      "code": "(() => { const wanted = `{ADVERTISER}`.trim().toLowerCase(); const option = [...document.querySelectorAll(\"li[id^='pageID:'], [role='option']\")].find((el) => (el.innerText || '').toLowerCase().includes(wanted)); if (!option) throw new Error(`Advertiser option not found: ${wanted}`); option.click(); return { clicked: (option.innerText || '').trim() }; })()",
      "description": "Open the matching Meta advertiser page"
    },
    {
      "action": "wait",
      "ms": 2500,
      "description": "Wait for Meta advertiser results"
    },
    {
      "action": "browser_js",
      "code": "(() => { const text = document.body.innerText; const results = text.match(/~\\d+ results/)?.[0] || null; const snippets = text.split(/Active\\nLibrary ID:/).slice(1, 5).map((chunk) => (`Library ID:${chunk}`).slice(0, 1200)); return { advertiser: `{ADVERTISER}`, url: location.href, results, snippets }; })()",
      "description": "Extract Meta ad count and visible snippets"
    },
    {
      "action": "screenshot",
      "description": "Capture the final Meta state",
      "optional": true
    }
  ]
}
