Skip to content

Commit d50b17c

Browse files
committed
Merge remote-tracking branch 'origin/staging' into codex/ashby-integration-expansion
2 parents 2f02cbb + b1b5de7 commit d50b17c

4 files changed

Lines changed: 237 additions & 4 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { cn } from '@sim/emcn'
2+
import type { IntegrationComparisonContent } from '@/app/(landing)/integrations/data/types'
3+
4+
interface IntegrationComparisonSectionProps {
5+
comparison: IntegrationComparisonContent
6+
}
7+
8+
/**
9+
* Renders a compact, server-side comparison with a horizontally scrollable
10+
* mobile layout and a sticky capability column for row context.
11+
*/
12+
export function IntegrationComparisonSection({ comparison }: IntegrationComparisonSectionProps) {
13+
const headingId = `${comparison.id}-heading`
14+
15+
return (
16+
<section id={comparison.id} aria-labelledby={headingId} className='px-6 py-10'>
17+
<h2
18+
id={headingId}
19+
className='mb-4 text-[var(--text-primary)] text-xl leading-[100%] tracking-[-0.02em]'
20+
>
21+
{comparison.heading}
22+
</h2>
23+
<p className='mb-6 max-w-[900px] text-[var(--text-body)] text-sm leading-[150%] tracking-[0.02em]'>
24+
{comparison.intro}
25+
</p>
26+
27+
<div className='w-full overflow-x-auto rounded-xl border border-[var(--border-1)]'>
28+
<table className='w-full min-w-[860px] table-fixed border-separate border-spacing-0 text-left'>
29+
<caption className='sr-only'>{comparison.heading}</caption>
30+
<colgroup>
31+
<col className='w-[22%]' />
32+
{comparison.columns.map((column) => (
33+
<col key={column} className='w-[19.5%]' />
34+
))}
35+
</colgroup>
36+
<thead>
37+
<tr>
38+
<th
39+
scope='col'
40+
className='sticky left-0 z-10 bg-[var(--surface-1)] px-4 py-3 font-medium text-[var(--text-muted)] text-small'
41+
>
42+
<span className='sr-only'>Capability</span>
43+
</th>
44+
{comparison.columns.map((column, index) => (
45+
<th
46+
key={column}
47+
scope='col'
48+
className={cn(
49+
'border-[var(--border)] border-l px-4 py-3 font-medium text-[var(--text-primary)] text-small',
50+
index === 0 ? 'bg-[var(--surface-2)]' : 'bg-[var(--surface-1)]'
51+
)}
52+
>
53+
{column}
54+
</th>
55+
))}
56+
</tr>
57+
</thead>
58+
<tbody>
59+
{comparison.rows.map((row) => (
60+
<tr key={row.label}>
61+
<th
62+
scope='row'
63+
className='sticky left-0 z-10 border-[var(--border)] border-t bg-[var(--surface-1)] px-4 py-3 align-top font-medium text-[var(--text-primary)] text-small leading-[150%]'
64+
>
65+
{row.label}
66+
</th>
67+
{row.values.map((value, index) => (
68+
<td
69+
key={comparison.columns[index]}
70+
className={cn(
71+
'border-[var(--border)] border-t border-l px-4 py-3 align-top text-[var(--text-body)] text-small leading-[150%]',
72+
index === 0 ? 'bg-[var(--surface-2)]' : 'bg-[var(--surface-1)]'
73+
)}
74+
>
75+
{value.href ? (
76+
<a
77+
href={value.href}
78+
target='_blank'
79+
rel='noopener noreferrer'
80+
className='underline decoration-[var(--border-1)] underline-offset-2 transition-colors hover:text-[var(--text-primary)]'
81+
>
82+
{value.text}
83+
</a>
84+
) : (
85+
value.text
86+
)}
87+
</td>
88+
))}
89+
</tr>
90+
))}
91+
</tbody>
92+
</table>
93+
</div>
94+
95+
<p className='mt-6 max-w-[900px] text-[var(--text-body)] text-sm leading-[150%] tracking-[0.02em]'>
96+
{comparison.conclusion}
97+
</p>
98+
</section>
99+
)
100+
}

apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { BackLink } from '@/app/(landing)/components'
1818
import { JsonLd } from '@/app/(landing)/components/json-ld'
1919
import { LandingFAQ } from '@/app/(landing)/components/landing-faq'
2020
import { ShareButton } from '@/app/(landing)/components/share-button'
21+
import { IntegrationComparisonSection } from '@/app/(landing)/integrations/(shell)/[slug]/components/integration-comparison-section/integration-comparison-section'
2122
import { IntegrationCtaButton } from '@/app/(landing)/integrations/(shell)/[slug]/components/integration-cta-button'
2223
import { TemplateCardButton } from '@/app/(landing)/integrations/(shell)/[slug]/components/template-card-button'
2324
import { IntegrationIcon } from '@/app/(landing)/integrations/components/integration-icon'
@@ -391,10 +392,12 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
391392
const relatedIntegrations = relatedSlugs
392393
.map((s) => bySlug.get(s))
393394
.filter((i): i is Integration => i !== undefined)
394-
const faqs = buildFAQs(
395-
integration,
396-
relatedIntegrations.map((i) => i.name)
397-
)
395+
const faqs =
396+
seo?.faqs ??
397+
buildFAQs(
398+
integration,
399+
relatedIntegrations.map((i) => i.name)
400+
)
398401
const matchingTemplates = getTemplatesForBlock(integration.type)
399402
.sort(
400403
(a, b) =>
@@ -685,6 +688,13 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
685688

686689
<div className='h-px w-full bg-[var(--border)]' />
687690

691+
{seo?.comparison && (
692+
<>
693+
<IntegrationComparisonSection comparison={seo.comparison} />
694+
<div className='h-px w-full bg-[var(--border)]' />
695+
</>
696+
)}
697+
688698
{/* Triggers - rows */}
689699
{triggers.length > 0 && (
690700
<section aria-labelledby='triggers-heading'>

apps/sim/app/(landing)/integrations/data/seo-content.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,101 @@ export const INTEGRATION_SEO: Record<string, IntegrationSeoContent> = {
7070
toolsSubtitleSuffix:
7171
' across messaging, channels, threads, users, reactions and files, and canvases and views. Combine multiple Slack actions in one workflow to summarise a message, route it, update a ticket, and post the ticket update back in Slack',
7272
},
73+
'twilio-sms': {
74+
tagline:
75+
'Sim connects to Twilio to let an AI agent send SMS updates when an order status changes. Connect Twilio SMS to Sim to send outbound messages and start AI workflows when Twilio reports an inbound SMS, inbound MMS, or message status change.',
76+
overview:
77+
'The Twilio SMS block sends outbound messages. Twilio SMS Received and Twilio Message Status triggers start Sim workflows from supported webhook events.',
78+
comparison: {
79+
id: 'twilio-sms-comparison',
80+
heading: 'Sim vs. Zapier, Make, and n8n for Twilio SMS',
81+
intro:
82+
"Zapier, Make, and n8n provide Twilio integrations for general-purpose automation. Sim focuses on AI workflows that use Agent blocks to draft or transform messages with order or customer data before a Twilio SMS block sends them. Supported Twilio webhooks can start Sim workflows without scheduled polling. Zapier, Make, or n8n may suit a Twilio workflow that does not require Sim's Agent blocks.",
83+
columns: ['Sim', 'Zapier', 'Make', 'n8n'],
84+
rows: [
85+
{
86+
label: 'Trigger model',
87+
values: [
88+
{ text: 'Real-time webhook' },
89+
{
90+
text: 'Polling for new SMS',
91+
href: 'https://zapier.com/apps/twilio/integrations',
92+
},
93+
{
94+
text: 'Instant webhook',
95+
href: 'https://apps.make.com/twilio',
96+
},
97+
{
98+
text: 'Webhook',
99+
href: 'https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.twiliotrigger/',
100+
},
101+
],
102+
},
103+
{
104+
label: 'AI drafting before send',
105+
values: [
106+
{ text: 'Agent block, built in' },
107+
{
108+
text: 'Requires a separate AI step or app',
109+
href: 'https://zapier.com/apps/twilio/integrations/chatgpt',
110+
},
111+
{
112+
text: 'Requires a separate AI step or app',
113+
href: 'https://www.make.com/en/integrations/twilio/openai-gpt-3',
114+
},
115+
{
116+
text: 'Requires a separate AI node',
117+
href: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent/',
118+
},
119+
],
120+
},
121+
{
122+
label: 'Free to start',
123+
values: [
124+
{ text: 'Yes' },
125+
{
126+
text: 'Yes, with a limited free tier',
127+
href: 'https://zapier.com/pricing',
128+
},
129+
{
130+
text: 'Yes, with a limited free tier',
131+
href: 'https://www.make.com/en/pricing',
132+
},
133+
{
134+
text: 'Yes, when self-hosted',
135+
href: 'https://docs.n8n.io/privacy-and-security/sustainable-use-license/',
136+
},
137+
],
138+
},
139+
],
140+
conclusion:
141+
'Choose Sim when the workflow needs an AI agent to read order or customer context and write the message, rather than relay a fixed template.',
142+
},
143+
triggersIntro:
144+
'A supported Twilio SMS webhook starts a Sim workflow when Sim receives the corresponding event. Webhook delivery removes the need for scheduled polling, but Twilio processing and network conditions can affect when Sim receives an event.',
145+
faqs: [
146+
{
147+
question: 'What can I do with the Twilio SMS integration?',
148+
answer:
149+
"Sim's Twilio SMS integration lets an AI agent send SMS messages and receive SMS or MMS messages inside a workflow. You can combine Twilio SMS with Agent blocks and integrations such as AgentPhone and Discord. Combining these blocks lets you generate messages and coordinate responses across supported tools in one workflow.",
150+
},
151+
{
152+
question: 'How do I connect Twilio SMS to Sim?',
153+
answer:
154+
'A Twilio SMS connection authorizes Sim to use the Twilio actions and triggers you configure. Create an account at sim.ai, add a Twilio SMS block to a workflow, and enter the Twilio credentials requested in the connection settings. After you choose an action or trigger and test the workflow, you can deploy it to process supported Twilio events.',
155+
},
156+
{
157+
question: 'How do Twilio SMS triggers work?',
158+
answer:
159+
'A Twilio SMS trigger starts a Sim workflow when its webhook receives a supported Twilio event. Add a trigger block to the workflow, then configure the generated webhook URL in the relevant Twilio settings for Twilio SMS Received or Twilio Message Status events. The configured webhooks start matching workflows without scheduled polling.',
160+
},
161+
{
162+
question: 'What data does a Twilio SMS trigger provide?',
163+
answer:
164+
'A Twilio SMS trigger provides the fields in the webhook payload that Twilio sends to Sim. Twilio SMS Received events include data about an inbound SMS or MMS, which the workflow can pass to Agent blocks or later steps. Available fields vary by event and payload, so inspect a test event before mapping them.',
165+
},
166+
],
167+
},
73168
airtable: {
74169
title: 'Airtable Automation with Sim',
75170
description:

apps/sim/app/(landing)/integrations/data/types.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,30 @@ export interface IntegrationLandingContent {
2929
aiDisclaimer?: string
3030
}
3131

32+
export interface IntegrationComparisonRow {
33+
label: string
34+
values: IntegrationComparisonValue[]
35+
}
36+
37+
export interface IntegrationComparisonValue {
38+
text: string
39+
href?: string
40+
}
41+
42+
export interface IntegrationComparisonContent {
43+
id: string
44+
heading: string
45+
intro: string
46+
columns: string[]
47+
rows: IntegrationComparisonRow[]
48+
conclusion: string
49+
}
50+
51+
export interface IntegrationFaqContent {
52+
question: string
53+
answer: string
54+
}
55+
3256
/**
3357
* Hand-authored, per-integration SEO/GEO overrides keyed by slug. Unlike
3458
* {@link IntegrationLandingContent}, this is consumed at render time directly by
@@ -57,6 +81,10 @@ export interface IntegrationSeoContent {
5781
triggersIntro?: string
5882
/** Agent-templates intro paragraph, overriding the generated default. */
5983
templatesIntro?: string
84+
/** Optional comparison section rendered immediately before real-time triggers. */
85+
comparison?: IntegrationComparisonContent
86+
/** Full FAQ replacement for integrations with hand-authored answers. */
87+
faqs?: IntegrationFaqContent[]
6088
/**
6189
* Text appended to the `"{n} {name} tool(s) available in Sim"` subtitle (e.g.
6290
* `" for Confluence automation across pages, blog posts, …"`). Keeps the tool

0 commit comments

Comments
 (0)