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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.omni.co/feedback

```json
{
  "path": "/guides/index",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Guides

> Step-by-step tutorials and best practices for getting the most out of Omni.

export const guides = [{
  "title": "Improving AI answer quality",
  "description": "Learn practical steps to improve AI answer quality in Omni by optimizing data modeling, testing AI responses, and monitoring usage patterns.",
  "href": "/guides/ai/improve-ai-answer-quality",
  "tags": ["ai"]
}, {
  "title": "Tuning Omni AI for cost and quality",
  "description": "Balance AI cost and quality for your organization by combining ai_settings parameters into profiles that fit your use cases.",
  "href": "/guides/ai/tuning-cost-quality",
  "tags": ["ai", "modeling"]
}, {
  "title": "Set up connection environments with the API",
  "description": "Configure dev and prod connection environments with the API.",
  "href": "/guides/api/connection-environments",
  "tags": ["api"]
}, {
  "title": "Build a data lineage integration with the Omni API",
  "description": "Build OpenMetadata / DataHub integrations using the Omni REST API",
  "href": "/guides/api/data-lineage-integration",
  "tags": ["api", "patterns"]
}, {
  "title": "Port SQL queries into an Omni workbook via API",
  "description": "Use a bash script to build Omni tabs and tiles via the Omni API.",
  "href": "/guides/api/port-sql-queries-omni-api",
  "tags": ["api"]
}, {
  "title": "Run document queries with the Query API",
  "description": "Programmatically run document queries with the Omni API.",
  "href": "/guides/api/run-document-queries",
  "tags": ["api"]
}, {
  "title": "Enforce database RBAC in Omni with connection environments",
  "description": "Use database-level roles to manage data access, audit logging, and resource allocation in Omni.",
  "href": "/guides/connections/enforce-database-rbac",
  "tags": ["connections"]
}, {
  "title": "Filter dashboard charts with calculated fields",
  "description": "Create a dashboard filter using a calculated field in the underlying query.",
  "href": "/guides/dashboards/calculated-field-filter",
  "tags": ["dashboards", "filters"]
}, {
  "title": "Dashboard best practices",
  "description": "Tips and patterns from the Omni team to help you build dashboards your whole org actually wants to use.",
  "href": "/guides/dashboards/dashboarding-best-practices",
  "tags": ["dashboards", "design", "best practices"]
}, {
  "title": "Connect a chat agent to Omni AI for embed experiences",
  "description": "Use the Omni AI API or MCP Server to connect a custom chat agent that queries data on behalf of embed users, scoped to each users permissions.",
  "href": "/guides/embed/ai-chat-agent",
  "tags": ["embed", "ai"]
}, {
  "title": "Embedding Omni into internal applications",
  "description": "Embed Omni into internal apps such as wikis, Salesforce, Notion, or any other website that supports iframes.",
  "href": "/guides/embed/omni-in-internal-app",
  "tags": ["embed"]
}, {
  "title": "Embedding Omni in your Notion instance",
  "description": "Embed Omni dashboards in Notion documents using iframes.",
  "href": "/guides/embed/omni-in-notion",
  "tags": ["embed"]
}, {
  "title": "Embedding Omni in your Salesforce instance",
  "description": "Embed static and dynamic Omni dashboards in Salesforce using Visualforce pages and tabs.",
  "href": "/guides/embed/omni-in-salesforce",
  "tags": ["embed"]
}, {
  "title": "Resolve Join fans out data without primary key errors",
  "description": "Learn to account for fan out in table joins.",
  "href": "/guides/errors/fan-out-without-pk",
  "tags": ["errors"]
}, {
  "title": "Improving date flexibility with templated filters",
  "description": "A guide to going beyond the out of the box controls to give users more flexibility to manipulate dates by utilizing templated filters.",
  "href": "/guides/modeling/date-flexibility-templated-filters",
  "tags": ["modeling"]
}, {
  "title": "Join to the same table twice",
  "description": "Use aliases to build tables named with language already familiar to your users.",
  "href": "/guides/modeling/join-to-same-table",
  "tags": ["modeling"]
}, {
  "title": "Local development with the model editor CLI",
  "description": "Edit Omni model YAML files locally in your preferred editor with real-time sync back to Omni.",
  "href": "/guides/modeling/local-development",
  "tags": ["modeling", "ai"]
}, {
  "title": "Organize fields with nested groups",
  "description": "Keep workbook field browsers navigable by grouping related fields.",
  "href": "/guides/modeling/nested-field-groups",
  "tags": ["modeling"]
}, {
  "title": "Preview dbt changes in Omni before merging to production",
  "description": "Preview dbt model changes, including net-new tables and views, in an Omni development environment before merging to production.",
  "href": "/guides/modeling/preview-dbt-changes",
  "tags": ["modeling", "dbt"]
}, {
  "title": "Push Omni topics to Databricks as metric views",
  "description": "Use the Omni Python SDK to generate Databricks metric view DDL from an Omni topic.",
  "href": "/guides/modeling/push-to-databricks-metric-views",
  "tags": ["modeling"]
}, {
  "title": "Deploying Omni at scale with shared model extensions",
  "description": "Learn how to use Shared Model Extensions to manage large Omni deployments across multiple data teams.",
  "href": "/guides/modeling/scaled-deployments-shared-model-extensions",
  "tags": ["modeling"]
}, {
  "title": "Apply a filter to a single measure",
  "description": "Add a filter to just one measure in a given query.",
  "href": "/guides/modeling/single-field-filter",
  "tags": ["modeling"]
}, {
  "title": "Using Level of Detail functions for cohorting analysis",
  "description": "Utilize Level of Detail fields to create a cohort analysis for determining how different cohorts of user perform over time.",
  "href": "/guides/patterns/build-cohort-analysis-using-level-of-detail",
  "tags": ["patterns"]
}, {
  "title": "Using AI to build a cohort analysis with month offset",
  "description": "Use the Omni Agent to create a cohort analysis that tracks user behavior over time using monthly offsets.",
  "href": "/guides/patterns/cohort-analysis-month-offset-ai",
  "tags": ["patterns"]
}, {
  "title": "Optimizing AI context for fintech and banking",
  "description": "A hands-on guide to configuring AI context at the model, topic, and view levels using a fintech example.",
  "href": "/guides/patterns/optimizing-ai-context-for-fintech",
  "tags": ["patterns", "ai"]
}, {
  "title": "Optimizing AI context for retail and ecommerce",
  "description": "A hands-on guide to configuring AI context at the model, topic, and view levels using a retail and ecommerce example.",
  "href": "/guides/patterns/optimizing-ai-context-for-retail-and-ecommerce",
  "tags": ["patterns", "ai"]
}, {
  "title": "Optimizing AI context for SaaS and sales operations",
  "description": "A hands-on guide to configuring AI context at the model, topic, and view levels using a SaaS and Salesforce example.",
  "href": "/guides/patterns/optimizing-ai-context-for-saas-and-sales-operations",
  "tags": ["patterns", "ai"]
}, {
  "title": "Optimizing AI context for support operations",
  "description": "Configure AI context across model, topic, and view levels to optimize Omnis AI for support operations.",
  "href": "/guides/patterns/optimizing-ai-context-for-support-operations",
  "tags": ["patterns", "ai"]
}, {
  "title": "Optimizing AI context for Media and AdTech",
  "description": "A hands-on guide to configuring AI context at the model, topic, and view levels using a Media and AdTech example.",
  "href": "/guides/patterns/optimizing-ai-context-media-and-adtech",
  "tags": ["patterns", "ai"]
}, {
  "title": "Building a basic cohort analysis with pivots",
  "description": "Build a cohort analysis using pivots in Omni to track user retention, engagement, and behavior over time.",
  "href": "/guides/patterns/simple-cohort-analysis-pivot",
  "tags": ["patterns"]
}, {
  "title": "Cohort analysis using a thin spine",
  "description": "Build cohort analyses using thin dimensional spines.",
  "href": "/guides/patterns/spine-cohort-analysis",
  "tags": ["patterns"]
}, {
  "title": "Thin dimensional spine for multi-fact event analysis",
  "description": "Analyze multiple event streams together without fanout using a thin dimensional spine.",
  "href": "/guides/patterns/thin-dimension-spine",
  "tags": ["patterns"]
}, {
  "title": "Add links to visualizations",
  "description": "Encourage self-service data exploration by adding links to other dashboards to your visualizations.",
  "href": "/guides/visualizations/add-links",
  "tags": ["visualizations"]
}, {
  "title": "Customize drill fields",
  "description": "Curate the columns displayed to users when drilling.",
  "href": "/guides/workbooks/custom-drill-fields",
  "tags": ["workbooks"]
}, {
  "title": "Point-in-time snapshots with parameters",
  "description": "How to use Mustache syntax to dynamically modify a query view",
  "href": "/guides/workbooks/snapshots-with-parameters",
  "tags": ["workbooks"]
}];

export const categoryIcons = {
  'administration': 'lock',
  'api': 'terminal',
  'connections': 'database',
  'dashboards': 'table-columns',
  'embed': 'code',
  'errors': 'exclamation',
  'modeling': 'wrench',
  'patterns': 'plus',
  'schedules & alerts': 'envelope',
  'visualizations': 'chart-column',
  'workbooks': 'book'
};

export const GuidesFilter = ({guides, categoryIcons}) => {
  const getIconForGuide = guide => {
    const category = guide.tags.find(tag => categoryIcons[tag.toLowerCase()]);
    return category ? categoryIcons[category.toLowerCase()] : 'book';
  };
  const allTags = [...new Set(guides.flatMap(g => g.tags))].sort();
  const [search, setSearch] = React.useState('');
  const [selectedTags, setSelectedTags] = React.useState([]);
  const toggleTag = tag => {
    setSelectedTags(prev => prev.includes(tag) ? prev.filter(t => t !== tag) : [...prev, tag]);
  };
  const filteredGuides = React.useMemo(() => {
    return guides.filter(guide => {
      if (search) {
        const searchLower = search.toLowerCase();
        const matchesSearch = guide.title.toLowerCase().includes(searchLower) || guide.description.toLowerCase().includes(searchLower) || guide.tags.some(tag => tag.toLowerCase().includes(searchLower));
        if (!matchesSearch) return false;
      }
      if (selectedTags.length > 0 && !selectedTags.some(tag => guide.tags.includes(tag))) return false;
      return true;
    });
  }, [search, selectedTags]);
  const hasActiveFilters = search || selectedTags.length > 0;
  const clearFilters = () => {
    setSearch('');
    setSelectedTags([]);
  };
  return <div className="guides-layout">
      {}
      <aside className="guides-sidebar">
        <div className="guides-filters">
          {hasActiveFilters && <button onClick={clearFilters} className="guides-clear-button">
              Clear all filters
            </button>}

          <div className="guides-filter-group">
            <label className="guides-filter-label">Search</label>
            <input type="text" placeholder="Search guides..." value={search} onChange={e => setSearch(e.target.value)} className="guides-filter-input" />
          </div>

          <div className="guides-filter-group">
            <label className="guides-filter-label">Topics</label>
            {allTags.map(tag => <button key={tag} onClick={() => toggleTag(tag)} className={`guides-filter-button ${selectedTags.includes(tag) ? 'active' : ''}`}>
                {tag}
              </button>)}
          </div>
        </div>
      </aside>

      {}
      <main className="guides-content">
        <div className="guides-results-count">
          {filteredGuides.length} {filteredGuides.length === 1 ? 'guide' : 'guides'}
        </div>

        {filteredGuides.length > 0 ? <div className="guides-grid">
            {filteredGuides.map(guide => <a key={guide.href} href={guide.href} className="guides-card">
                <div className="guides-card-icon">
                  <Icon icon={getIconForGuide(guide)} iconType="solid" color="#FF5789" size={24} />
                </div>
                <h3 className="guides-card-title">{guide.title}</h3>
                {guide.description && <p className="guides-card-description">{guide.description}</p>}
                {guide.tags.length > 0 && <div className="guides-card-meta">
                    {guide.tags.slice(0, 3).map(tag => <span key={tag} className="guides-card-tag">{tag}</span>)}
                  </div>}
              </a>)}
          </div> : <div className="guides-no-results">
            <p>No guides match your filters.</p>
            <button onClick={clearFilters} className="guides-clear-button">
              Clear filters
            </button>
          </div>}
      </main>
    </div>;
};

<div className="guides-container">
  <h1 className="guides-title">Guides</h1>

  <p className="guides-description">
    Step-by-step tutorials and best practices for getting the most out of Omni.
  </p>

  <GuidesFilter guides={guides} categoryIcons={categoryIcons} />
</div>
