import type { Metadata } from 'next' import type { SearchParams } from 'nuqs/server' import { SITE_URL } from '@/lib/core/utils/urls' import { blockTypeToIconMap, type FAQItem, INTEGRATIONS, type Integration, POPULAR_WORKFLOWS, } from '@/lib/integrations' import { withFilteredNoindex } from '@/lib/landing/seo' import { JsonLd } from '@/app/(landing)/components/json-ld' import { LandingFAQ } from '@/app/(landing)/components/landing-faq' import { IntegrationCard } from '@/app/(landing)/integrations/components/integration-card' import { IntegrationGrid } from '@/app/(landing)/integrations/components/integration-grid' import { RequestIntegrationModal } from '@/app/(landing)/integrations/components/request-integration-modal' import { integrationsSearchParamsCache } from '@/app/(landing)/integrations/search-params' const allIntegrations = INTEGRATIONS const INTEGRATION_COUNT = allIntegrations.length const OAUTH_COUNT = allIntegrations.filter((i) => i.authType === 'oauth').length const TRIGGER_INTEGRATION_COUNT = allIntegrations.filter((i) => i.triggerCount > 0).length const TOTAL_TOOL_COUNT = allIntegrations.reduce((sum, i) => sum + i.operationCount, 0) /** * Catalog-level FAQ. Questions that read the same for every integration live * here exactly once instead of repeating across all per-integration pages. */ const CATALOG_FAQS: FAQItem[] = [ { question: 'How do integrations work in Sim?', answer: `Each integration is a block you drag onto Sim's workflow builder. Together, Sim's ${INTEGRATION_COUNT} integrations expose ${TOTAL_TOOL_COUNT}+ tools that AI agents can call. ${OAUTH_COUNT} connect with one-click OAuth, and the rest use an API key or no authentication at all. Wire blocks together, add an AI agent block for reasoning, and run.`, }, { question: 'Are Sim integrations free to use?', answer: `Yes. Sim's free plan includes every integration in the library, all ${INTEGRATION_COUNT} of them, with no credit card required. Create an account at sim.ai and start building.`, }, { question: 'Can an AI agent decide when to use an integration?', answer: `Yes. This is the core of Sim. You give an agent access to integration tools and describe the goal in plain language; the agent decides which tools to call, in what order, and how to handle the results. Automations adapt to context instead of breaking when inputs change.`, }, { question: 'Can external events trigger my agents automatically?', answer: `Yes. ${TRIGGER_INTEGRATION_COUNT} Sim integrations include real-time webhook triggers. Add a trigger block to your agent, copy its webhook URL into the external service, and every matching event starts your agent instantly, no polling, no delay.`, }, { question: 'How many integrations does Sim support?', answer: `Sim supports ${INTEGRATION_COUNT} integrations across messaging, CRMs, databases, developer tools, AI providers, and more, and the catalog grows continually. If a tool you need is missing, request it below and we'll prioritize it.`, }, ] /** * Unique integration names that appear in popular workflow pairs. * Used for metadata keywords so they stay in sync automatically. */ const TOP_NAMES = [...new Set(POPULAR_WORKFLOWS.flatMap((p) => [p.from, p.to]))].slice(0, 6) const baseUrl = SITE_URL const INTEGRATIONS_BREADCRUMB_JSON_LD = { '@context': 'https://schema.org', '@type': 'BreadcrumbList', itemListElement: [ { '@type': 'ListItem', position: 1, name: 'Home', item: baseUrl }, { '@type': 'ListItem', position: 2, name: 'Integrations', item: `${baseUrl}/integrations`, }, ], } /** Curated featured integrations - high-recognition services shown as cards. */ const FEATURED_SLUGS = ['slack', 'notion', 'github', 'gmail'] as const const bySlug = new Map(allIntegrations.map((i) => [i.slug, i])) const featured = FEATURED_SLUGS.map((s) => bySlug.get(s)).filter( (i): i is Integration => i !== undefined ) /** * `q`/`category` render a genuinely different server-rendered list (see * search-params.ts), so filtered URLs are noindexed rather than * self-canonicalized — keeps the single indexable URL as the bare catalog * page instead of asking Google to index every filter permutation. */ export async function generateMetadata({ searchParams, }: { searchParams: Promise }): Promise { const { q, category } = await integrationsSearchParamsCache.parse(searchParams) const isFiltered = Boolean(q || category) return withFilteredNoindex( { title: 'Integrations', description: `Connect ${INTEGRATION_COUNT}+ apps and services in Sim's AI workspace. Build agents that automate real work with ${TOP_NAMES.join(', ')}, and more.`, keywords: [ 'AI workspace integrations', 'AI agent integrations', 'AI agent builder integrations', ...TOP_NAMES.flatMap((n) => [`${n} integration`, `${n} automation`]), ...allIntegrations.slice(0, 20).map((i) => `${i.name} automation`), ], // og:image/twitter:image come from the sibling opengraph-image.tsx - // Next serves it at a hash-suffixed URL, so hardcoding it here 404s. openGraph: { title: 'Integrations | Sim AI Workspace', description: `Connect ${INTEGRATION_COUNT}+ apps in Sim's AI workspace. Build agents that link ${TOP_NAMES.join(', ')}, and every tool your team uses.`, url: `${baseUrl}/integrations`, type: 'website', }, twitter: { card: 'summary_large_image', title: 'Integrations | Sim', description: `Connect ${INTEGRATION_COUNT}+ apps in Sim's AI workspace.`, }, alternates: { canonical: `${baseUrl}/integrations` }, }, isFiltered ) } export default async function IntegrationsPage({ searchParams, }: { searchParams: Promise }) { await integrationsSearchParamsCache.parse(searchParams) const itemListJsonLd = { '@context': 'https://schema.org', '@type': 'ItemList', name: 'Sim AI Workflow Integrations', description: `Complete list of ${INTEGRATION_COUNT}+ integrations available in Sim's AI workspace for building and deploying AI agents.`, url: `${baseUrl}/integrations`, numberOfItems: INTEGRATION_COUNT, itemListElement: allIntegrations.map((integration, index) => ({ '@type': 'ListItem', position: index + 1, item: { '@type': 'SoftwareApplication', name: integration.name, description: integration.description, url: `${baseUrl}/integrations/${integration.slug}`, applicationCategory: 'BusinessApplication', featureList: integration.operations.map((o) => o.name), }, })), } const faqJsonLd = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: CATALOG_FAQS.map(({ question, answer }) => ({ '@type': 'Question', name: question, acceptedAnswer: { '@type': 'Answer', text: answer }, })), } return (
{/* Hero */}

Integrations

Connect every tool your team uses. Build agents that automate real work across{' '} {INTEGRATION_COUNT} apps and services.

{/* Full-width divider */}
{/* Border-railed content */}
{/* Featured integrations - top */} {featured.length > 0 && ( <>
)} {/* All Integrations - search, filters, rows */}

All Integrations

{/* FAQ */}

Frequently asked questions

{/* Integration request */}

Don't see the integration you need?

Let us know and we'll prioritize it.

{/* Closing full-width divider */}
) }