> ## Documentation Index
> Fetch the complete documentation index at: https://www.conductor.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Template Gallery

export const DownloadAllButton = () => {
  const GALLERY_DOWNLOAD_HREF = '/templates/files/downloads/conductor-all-templates.zip';
  const GALLERY_DOWNLOAD_FILENAME = 'conductor-all-templates.zip';
  const GALLERY_DOWNLOAD_PREPARING_MS = 2200;
  const GALLERY_DOWNLOAD_REMINDER_MS = 4500;
  const downloadIcon = size => <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
      <path d="M12 15V3" />
      <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
      <path d="m7 10 5 5 5-5" />
    </svg>;
  const [toast, setToast] = useState(null);
  const [active, setActive] = useState(false);
  const timersRef = useRef([]);
  const clearTimers = useCallback(() => {
    timersRef.current.forEach(clearTimeout);
    timersRef.current = [];
  }, []);
  useEffect(() => clearTimers, [clearTimers]);
  const schedule = useCallback((fn, ms) => {
    const id = setTimeout(fn, ms);
    timersRef.current.push(id);
  }, []);
  const handleClick = useCallback(e => {
    if (active) {
      e.preventDefault();
      return;
    }
    clearTimers();
    setActive(true);
    setToast('preparing');
    schedule(() => setToast('reminder'), GALLERY_DOWNLOAD_PREPARING_MS);
    schedule(() => {
      setToast(null);
      setActive(false);
    }, GALLERY_DOWNLOAD_PREPARING_MS + GALLERY_DOWNLOAD_REMINDER_MS);
  }, [active, clearTimers, schedule]);
  return <div className="gallery-download-all-wrapper not-prose">
      <a href={GALLERY_DOWNLOAD_HREF} download={GALLERY_DOWNLOAD_FILENAME} className={active ? 'gallery-download-all-button gallery-download-all-button--active not-prose' : 'gallery-download-all-button not-prose'} aria-disabled={active ? 'true' : undefined} onClick={handleClick}>
        {downloadIcon(18)}
        Download All
      </a>

      {toast ? <div className="gallery-download-toast-host not-prose">
          {toast === 'preparing' ? <div className="gallery-download-toast gallery-download-toast--preparing not-prose" role="status" aria-live="polite">
              <div className="gallery-download-toast-header">
                <div className="gallery-download-toast-icon gallery-download-toast-icon--download" aria-hidden>
                  {downloadIcon(18)}
                </div>
                <div className="gallery-download-toast-text">
                  <span className="gallery-download-toast-title">
                    Download started
                  </span>
                  <span className="gallery-download-toast-subtitle">
                    Your download should begin shortly...
                  </span>
                </div>
              </div>
            </div> : <div className="gallery-download-toast gallery-download-toast--reminder not-prose" role="status" aria-live="polite">
              <div className="gallery-download-toast-header">
                <div className="gallery-download-toast-icon gallery-download-toast-icon--download" aria-hidden>
                  {downloadIcon(18)}
                </div>
                <div className="gallery-download-toast-text">
                  <span className="gallery-download-toast-title">
                    Check your downloads
                  </span>
                  <span className="gallery-download-toast-subtitle">
                    If it didn't start, click <strong>Download All</strong> again.
                  </span>
                </div>
              </div>
            </div>}
        </div> : null}
    </div>;
};

export const tagGroups = [{
  "id": "industry",
  "label": "Industry",
  "tags": [{
    "id": "industry-retail",
    "label": "Retail"
  }, {
    "id": "industry-b2b-saas",
    "label": "B2B SaaS"
  }, {
    "id": "industry-publishing",
    "label": "Publishing"
  }, {
    "id": "industry-agency",
    "label": "Agency"
  }, {
    "id": "industry-ecommerce",
    "label": "E-commerce"
  }]
}, {
  "id": "persona",
  "label": "Persona",
  "tags": [{
    "id": "persona-seo-aeo",
    "label": "SEO / AEO"
  }, {
    "id": "persona-web-technical",
    "label": "Web / Technical"
  }, {
    "id": "persona-content",
    "label": "Content"
  }, {
    "id": "persona-conductor-user",
    "label": "Conductor User"
  }, {
    "id": "persona-executive",
    "label": "Executive"
  }, {
    "id": "persona-e-commerce",
    "label": "E-Commerce"
  }, {
    "id": "persona-brand-pr",
    "label": "Brand / PR"
  }]
}, {
  "id": "product",
  "label": "Product",
  "tags": [{
    "id": "product-mcp",
    "label": "MCP"
  }, {
    "id": "product-data-api",
    "label": "Data API"
  }]
}, {
  "id": "use_case",
  "label": "Use case",
  "tags": [{
    "id": "use-case-aeo",
    "label": "AEO"
  }, {
    "id": "use-case-seo",
    "label": "SEO"
  }, {
    "id": "use-case-account-config",
    "label": "Account Config"
  }, {
    "id": "use-case-technical",
    "label": "Technical"
  }, {
    "id": "use-case-other",
    "label": "Other"
  }, {
    "id": "use-case-content",
    "label": "Content"
  }, {
    "id": "use-case-brand-research",
    "label": "Brand Research"
  }, {
    "id": "use-case-competitive",
    "label": "Competitive"
  }, {
    "id": "use-case-reporting",
    "label": "Reporting"
  }]
}];

export const templateItems = [{
  "href": "/templates/align-ai-and-traditional-tracking",
  "title": "Align AI and Traditional Tracking",
  "description": "Align your Conductor tracking across traditional and AI search so nothing falls through the cracks.",
  "tags": ["use-case-aeo", "use-case-seo", "use-case-account-config", "use-case-reporting", "persona-seo-aeo"]
}, {
  "href": "/templates/analyze-competitor-ai-content-strategies",
  "title": "Analyze Competitor AI Content Strategies",
  "description": "See exactly where competitors are beating you in AI search so you can plan how to overtake them.",
  "tags": ["use-case-aeo", "use-case-competitive", "use-case-content", "persona-content"]
}, {
  "href": "/templates/audit-your-brands-ai-search-visibility",
  "title": "Audit Your Brand's AI Search Visibility",
  "description": "Audit your brand's visibility, citations, and sentiment across ChatGPT, Gemini, Perplexity, and Google AI Overviews — with a prioritized action plan.",
  "tags": ["use-case-aeo", "use-case-brand-research", "use-case-competitive", "persona-seo-aeo", "persona-executive", "persona-brand-pr"]
}, {
  "href": "/templates/build-a-data-backed-content-strategy",
  "title": "Build a Data-Backed Content Strategy",
  "description": "Decide what to write — and whether to write or optimize — by grounding every choice in live AI citation data.",
  "tags": ["use-case-content", "persona-content"]
}, {
  "href": "/templates/build-board-ready-ai-search-deck",
  "title": "Build a Board-Ready AI Search Deck",
  "description": "Walk into a board meeting with a clear, defensible story about your brand's visibility in AI search.",
  "tags": ["use-case-aeo", "use-case-brand-research", "use-case-reporting", "persona-executive", "persona-brand-pr"]
}, {
  "href": "/templates/check-product-visibility-in-ai-shopping",
  "title": "Check Product Visibility in AI Shopping",
  "description": "Get your products recommended in AI shopping answers across ChatGPT, Gemini, Perplexity, and Google AI Mode.",
  "tags": ["use-case-aeo", "use-case-brand-research", "use-case-competitive", "use-case-reporting", "persona-e-commerce", "persona-brand-pr"]
}, {
  "href": "/templates/compare-mentions-in-ai-buying-recommendations",
  "title": "Compare Mentions in AI Buying Recommendations",
  "description": "See how you stack up against competitors in AI buying recommendations and what to build to start winning them.",
  "tags": ["use-case-aeo", "use-case-competitive", "use-case-reporting", "persona-e-commerce"]
}, {
  "href": "/templates/configure-ai-search-tracking",
  "title": "Configure AI Search Tracking",
  "description": "Get AI search tracking configured correctly from the start, with topics, engines, and prompts tuned to your business.",
  "tags": ["use-case-account-config", "persona-conductor-user"]
}, {
  "href": "/templates/diagnose-and-resolve-conductor-issues",
  "title": "Diagnose and Resolve Conductor Issues",
  "description": "Resolve Conductor issues faster by diagnosing in-chat and producing a clean escalation summary only when needed.",
  "tags": ["use-case-other", "persona-conductor-user"]
}, {
  "href": "/templates/find-ai-search-content-gaps",
  "title": "Find AI Search Content Gaps",
  "description": "Pinpoint which topics, personas, and intents competitors own in AI search so you can plan the catch-up.",
  "tags": ["use-case-content", "use-case-aeo", "use-case-competitive", "use-case-reporting", "persona-content"]
}, {
  "href": "/templates/map-your-ai-purchase-funnel",
  "title": "Map Your AI Purchase Funnel",
  "description": "See where shoppers drop out of your AI purchase funnel so you can close the gaps against competitors.",
  "tags": ["use-case-aeo", "use-case-competitive", "use-case-content", "use-case-reporting", "persona-e-commerce"]
}, {
  "href": "/templates/measure-ai-search-content-coverage",
  "title": "Measure AI Search Content Coverage",
  "description": "Know which pages and site sections are actually getting picked up in AI citations, and which aren't.",
  "tags": ["use-case-reporting", "use-case-aeo", "use-case-content", "persona-content"]
}, {
  "href": "/templates/read-ai-search-pulse-verdict",
  "title": "Read the AI Search Pulse Verdict",
  "description": "Get a 30-second verdict on whether your brand is winning or losing in AI search this week.",
  "tags": ["use-case-aeo", "use-case-reporting", "persona-executive", "persona-brand-pr"]
}, {
  "href": "/templates/scope-ai-search-analysis-settings",
  "title": "Scope AI Search Analysis Settings",
  "description": "Scope an AI search analysis to the specific site, engines, topics, personas, and intents that matter most.",
  "tags": ["use-case-content", "use-case-other", "use-case-aeo", "persona-content"]
}, {
  "href": "/templates/score-product-pages-for-ai-citations",
  "title": "Score Product Pages for AI Citations",
  "description": "Get a product or category page ready to be recommended by AI with a scored audit and fix list.",
  "tags": ["use-case-aeo", "use-case-content", "use-case-seo", "persona-e-commerce"]
}, {
  "href": "/templates/surface-unmet-ai-shopping-demand",
  "title": "Surface Unmet AI Shopping Demand",
  "description": "Find and prioritize the unmet shopping demand AI reveals in your category so you can act on it first.",
  "tags": ["use-case-aeo", "use-case-content", "use-case-competitive", "persona-e-commerce"]
}, {
  "href": "/templates/teach-your-llm-conductor",
  "title": "Teach Your LLM Conductor",
  "description": "Make every LLM answer about Conductor sound like it came from a seasoned Conductor expert.",
  "tags": ["use-case-other", "persona-conductor-user"]
}];

export function groupById(groups, id) {
  return groups.find(g => g.id === id) || null;
}

export function labelForTagId(groups, tagId) {
  for (const g of groups) {
    const hit = g.tags.find(t => t.id === tagId);
    if (hit) return hit.label;
  }
  return tagId;
}

export function firstTagInGroup(itemTags, group) {
  if (!group) return null;
  const allowed = new Set(group.tags.map(t => t.id));
  for (const id of itemTags) {
    if (allowed.has(id)) return id;
  }
  return null;
}

export function itemTagIdsInGroup(itemTags, group) {
  if (!group) return [];
  const allowed = new Set(group.tags.map(t => t.id));
  return itemTags.filter(id => allowed.has(id));
}

export function itemMatchesApplied(itemTags, appliedIds, group) {
  if (!appliedIds.length) return true;
  const inGroup = itemTagIdsInGroup(itemTags, group);
  return inGroup.some(id => appliedIds.includes(id));
}

export function TemplateCard(props) {
  const item = props.item;
  const groups = props.tagGroups;
  const aria = 'Template: ' + (item.title || 'Open template').replace(/^\s+|\s+$/g, '');
  const tagSlots = item.tags.map(tagId => ({
    key: tagId,
    label: labelForTagId(groups, tagId)
  }));
  return <a href={item.href} className="template-card not-prose" aria-label={aria}>
      <h3 className="template-card-title">{item.title}</h3>
      <p className="template-card-body">{item.description}</p>
      <div className="template-card-footer">
        <div className="template-card-rule" aria-hidden />
        <div className="template-tags">
          {tagSlots.map((t, index) => <span key={t.key} className={index % 2 === 0 ? 'template-tag template-tag-fill' : 'template-tag template-tag-outline'}>
              {t.label}
            </span>)}
        </div>
      </div>
    </a>;
}

export function ChevronDown(props) {
  return <svg viewBox="0 0 20 20" fill="currentColor" className={props.className} aria-hidden>
      <path fillRule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clipRule="evenodd" />
    </svg>;
}

export function SearchIcon(props) {
  return <svg viewBox="0 0 24 24" fill="none" className={props.className} aria-hidden>
      <path d="M10.5 18a7.5 7.5 0 100-15 7.5 7.5 0 000 15zM16.61 16.61l4.39 4.39" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
    </svg>;
}

export function FilterMenu(props) {
  const {menuId, triggerLabel, panelHeading, options, draftIds, setDraftIds, open, setOpen, onSubmit, onResetDraft} = props;
  const rootRef = useRef(null);
  useEffect(() => {
    if (!open) return;
    function onDocMouseDown(e) {
      if (rootRef.current && !rootRef.current.contains(e.target)) {
        setOpen(false);
      }
    }
    function onKey(e) {
      if (e.key === 'Escape') setOpen(false);
    }
    document.addEventListener('mousedown', onDocMouseDown);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDocMouseDown);
      document.removeEventListener('keydown', onKey);
    };
  }, [open, setOpen]);
  function toggleOption(id) {
    setDraftIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);
  }
  return <div className="relative min-w-0 flex-1" ref={rootRef}>
      <button type="button" className="flex w-full items-center justify-between gap-2 rounded-lg border border-slate-200 bg-white px-3 py-2.5 text-left text-sm font-medium text-slate-900 shadow-sm dark:border-slate-600 dark:bg-slate-900 dark:text-white" aria-expanded={open} aria-controls={menuId + '-panel'} id={menuId + '-trigger'} onClick={() => setOpen(!open)}>
        <span className="truncate">{triggerLabel}</span>
        <ChevronDown className="h-5 w-5 shrink-0 text-slate-500" />
      </button>
      {open ? <div id={menuId + '-panel'} role="dialog" aria-labelledby={menuId + '-trigger'} className="absolute left-0 right-0 z-50 mt-1 rounded-lg border border-slate-200 bg-white shadow-lg dark:border-slate-600 dark:bg-slate-900 sm:right-auto sm:min-w-[280px]">
          <div className="border-b border-slate-100 px-3 py-2.5 text-sm font-medium text-slate-900 dark:border-slate-700 dark:text-white">
            {panelHeading ?? triggerLabel}
          </div>
          <ul className="max-h-60 overflow-auto py-1">
            {options.map(opt => {
    const checked = draftIds.includes(opt.id);
    return <li key={opt.id}>
                  <label className="flex cursor-pointer items-center gap-2 px-3 py-2 text-sm text-slate-800 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-800">
                    <input type="checkbox" className="h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary" checked={checked} onChange={() => toggleOption(opt.id)} />
                    <span>{opt.label}</span>
                  </label>
                </li>;
  })}
          </ul>
          <div className="flex items-center justify-between gap-2 border-t border-slate-100 px-3 py-2.5 dark:border-slate-700">
            <button type="button" className="text-sm font-medium text-slate-900 underline decoration-slate-400 underline-offset-2 dark:text-white" onClick={onResetDraft}>
              Reset
            </button>
            <button type="button" className="rounded-md bg-primary px-3 py-1.5 text-xs font-semibold uppercase tracking-wide text-white" onClick={onSubmit}>
              Submit
            </button>
          </div>
        </div> : null}
    </div>;
}

export const TemplateGallery = () => {
  const personaGroup = useMemo(() => groupById(tagGroups, 'persona'), []);
  const useCaseGroup = useMemo(() => groupById(tagGroups, 'use_case'), []);
  const allItems = useMemo(() => templateItems, []);
  const [appliedPersonaIds, setAppliedPersonaIds] = useState([]);
  const [appliedUseCaseIds, setAppliedUseCaseIds] = useState([]);
  const [personaOpen, setPersonaOpen] = useState(false);
  const [useCaseOpen, setUseCaseOpen] = useState(false);
  const [draftPersonaIds, setDraftPersonaIds] = useState([]);
  const [draftUseCaseIds, setDraftUseCaseIds] = useState([]);
  const openPersona = useCallback(() => {
    setDraftPersonaIds([...appliedPersonaIds]);
    setPersonaOpen(true);
    setUseCaseOpen(false);
  }, [appliedPersonaIds]);
  const openUseCase = useCallback(() => {
    setDraftUseCaseIds([...appliedUseCaseIds]);
    setUseCaseOpen(true);
    setPersonaOpen(false);
  }, [appliedUseCaseIds]);
  const personaTriggerLabel = appliedPersonaIds.length === 0 ? 'Select your persona' : `${appliedPersonaIds.length} Persona${appliedPersonaIds.length === 1 ? '' : 's'} selected`;
  const useCaseTriggerLabel = appliedUseCaseIds.length === 0 ? 'Choose use case' : `${appliedUseCaseIds.length} Use case${appliedUseCaseIds.length === 1 ? '' : 's'} selected`;
  const filteredItems = useMemo(() => {
    return allItems.filter(item => {
      const okPersona = itemMatchesApplied(item.tags, appliedPersonaIds, personaGroup);
      const okUseCase = itemMatchesApplied(item.tags, appliedUseCaseIds, useCaseGroup);
      return okPersona && okUseCase;
    });
  }, [allItems, appliedPersonaIds, appliedUseCaseIds, personaGroup, useCaseGroup]);
  const hasActiveFilters = appliedPersonaIds.length > 0 || appliedUseCaseIds.length > 0;
  const showEmptyState = filteredItems.length === 0 && hasActiveFilters;
  const chipEntries = useMemo(() => {
    const rows = [];
    for (const id of appliedPersonaIds) {
      rows.push({
        axis: 'persona',
        id,
        label: labelForTagId(tagGroups, id)
      });
    }
    for (const id of appliedUseCaseIds) {
      rows.push({
        axis: 'use_case',
        id,
        label: labelForTagId(tagGroups, id)
      });
    }
    return rows;
  }, [appliedPersonaIds, appliedUseCaseIds]);
  function removeChip(axis, id) {
    if (axis === 'persona') {
      setAppliedPersonaIds(prev => prev.filter(x => x !== id));
    } else {
      setAppliedUseCaseIds(prev => prev.filter(x => x !== id));
    }
  }
  function resetAllFilters() {
    setAppliedPersonaIds([]);
    setAppliedUseCaseIds([]);
    setPersonaOpen(false);
    setUseCaseOpen(false);
  }
  return <div className="template-gallery-root not-prose">
      <div className="mb-8 flex flex-col gap-4 sm:flex-row sm:items-start">
        <FilterMenu menuId="gallery-persona-filter" triggerLabel={personaTriggerLabel} panelHeading="Select your persona" options={personaGroup ? personaGroup.tags : []} draftIds={draftPersonaIds} setDraftIds={setDraftPersonaIds} open={personaOpen} setOpen={v => {
    if (v) openPersona(); else setPersonaOpen(false);
  }} onSubmit={() => {
    setAppliedPersonaIds([...draftPersonaIds]);
    setPersonaOpen(false);
  }} onResetDraft={() => setDraftPersonaIds([])} />
        <FilterMenu menuId="gallery-use-case-filter" triggerLabel={useCaseTriggerLabel} panelHeading="Choose use case" options={useCaseGroup ? useCaseGroup.tags : []} draftIds={draftUseCaseIds} setDraftIds={setDraftUseCaseIds} open={useCaseOpen} setOpen={v => {
    if (v) openUseCase(); else setUseCaseOpen(false);
  }} onSubmit={() => {
    setAppliedUseCaseIds([...draftUseCaseIds]);
    setUseCaseOpen(false);
  }} onResetDraft={() => setDraftUseCaseIds([])} />
      </div>

      {hasActiveFilters ? <div className="mb-3 flex flex-wrap items-center gap-2">
          {chipEntries.map(c => <span key={c.axis + '-' + c.id} className="inline-flex items-center gap-1 rounded-full bg-slate-100 py-1 pl-2.5 pr-1 text-xs font-medium text-slate-800 dark:bg-slate-800 dark:text-slate-200">
              {c.label}
              <button type="button" className="rounded-full p-0.5 text-slate-500 hover:bg-slate-200 hover:text-slate-900 dark:hover:bg-slate-700 dark:hover:text-white" aria-label={'Remove filter ' + c.label} onClick={() => removeChip(c.axis, c.id)}>
                ×
              </button>
            </span>)}
          <button type="button" className="text-sm font-medium text-slate-900 underline decoration-slate-400 underline-offset-2 dark:text-white" onClick={resetAllFilters}>
            Reset filters
          </button>
        </div> : null}

      <p className="text-sm text-slate-500 dark:text-slate-400">
        {filteredItems.length} Template{filteredItems.length === 1 ? '' : 's'}{' '}
        available
      </p>

      {showEmptyState ? <div className="flex flex-col items-center justify-center py-16 text-center">
          <SearchIcon className="mx-auto h-14 w-14 text-primary opacity-90" />
          <h2 className="mt-6 font-display text-xl font-bold text-slate-900 dark:text-white">
            No templates found
          </h2>
          <p className="mt-3 max-w-md text-sm leading-relaxed text-slate-600 dark:text-slate-400">
            Try choosing a different persona and/or use case, or reset filters to see all
            templates. More templates are added over time.
          </p>
        </div> : <div className="mt-[40px] grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
          {filteredItems.map(item => <TemplateCard key={item.href} item={item} tagGroups={tagGroups} />)}
        </div>}
    </div>;
};

<div className="gallery-page-shell mx-auto max-w-7xl px-8 pb-24 md:px-12 not-prose">
  <section id="template-gallery-hero" className="home-hero" aria-labelledby="template-gallery-hero-heading">
    <div className="home-hero-grid">
      <div className="home-hero-primary">
        <p className="home-eyebrow">Conductor Template Gallery</p>

        <div id="template-gallery-hero-heading" className="home-hero-title" role="heading" aria-level="1">
          Everything your LLM needs to work with Conductor's data.
        </div>
      </div>

      <div className="home-hero-secondary home-hero-secondary--stacked">
        <p className="home-hero-lede">
          Download a skill, hand it to Claude, ChatGPT, or any agent—and
          get Conductor-grade AI-search analysis without having to write a prompt
          from scratch.
        </p>

        <DownloadAllButton />
      </div>
    </div>
  </section>

  <div className="mt-10 md:mt-12">
    <TemplateGallery />
  </div>

  <div className="help-cta mt-24 rounded-3xl px-6 text-center">
    <p className="mx-auto mt-4 max-w-md text-gray-600 dark:text-gray-300">
      Can't find what you're looking for? Our support team and community are here to help you
      succeed.
    </p>

    <div className="mt-10 flex flex-col justify-center gap-8 sm:flex-row">
      <a href="https://support.conductor.com" className="font-semibold text-gray-900 dark:text-white transition-all hover:text-primary">
        Knowledge Base
      </a>

      <a href="https://app.conductor.com/u/community" className="font-semibold text-gray-900 dark:text-white transition-all hover:text-primary">
        Community
      </a>
    </div>
  </div>
</div>
