Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,21 @@ function escapeRegex(value: string): string {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

/** True when at least one trigger is a genuine push webhook rather than a scheduled poller. */
function hasWebhookTrigger(triggers: { polling: boolean }[]): boolean {
return triggers.some((t) => !t.polling)
}

/** Describes a trigger set's delivery kind(s), covering the mixed case so it never mislabels a polling trigger as real-time. */
function triggerKindLabel(
triggers: { polling: boolean }[]
): 'scheduled' | 'real-time' | 'scheduled and real-time' {
const hasWebhook = hasWebhookTrigger(triggers)
const hasPolling = triggers.some((t) => t.polling)
if (hasWebhook && hasPolling) return 'scheduled and real-time'
return hasWebhook ? 'real-time' : 'scheduled'
}

/**
* Server-side rewrite of bare integration names in a curated template prompt
* to `@`-mention form (`Slack` → `@Slack`) so the prompt chips with brand
Expand Down Expand Up @@ -175,7 +190,7 @@ function TemplateIconRow({ allTypes }: { allTypes: string[] }) {
name={int?.name ?? bt}
Icon={ToolIcon}
as='span'
className='size-6 rounded-[4px]'
className='size-6 rounded-[4px] border border-[var(--border-1)]'
iconClassName='size-3.5'
fallbackClassName='text-[10px]'
aria-hidden='true'
Expand Down Expand Up @@ -209,12 +224,13 @@ function buildFAQs(integration: Integration, relatedNames: string[]): FAQItem[]
const faqDescription = sentenceWithTerminalPunctuation(description)
const opCount = operations.length
const triggerCount = triggers.length
const triggersArePolling = triggerCount > 0 && !hasWebhookTrigger(triggers)
const topOpNames = operations.slice(0, 5).map((o) => o.name)
const firstOp = operations[0]
const firstTrigger = triggers[0]
const pairings = relatedNames.slice(0, 2)
const toolsPhrase = `${opCount} ${name} tool${opCount === 1 ? '' : 's'}`
const triggersPhrase = `${triggerCount} real-time trigger${triggerCount === 1 ? '' : 's'}`
const triggersPhrase = `${triggerCount} ${triggerKindLabel(triggers)} trigger${triggerCount === 1 ? '' : 's'}`
const capabilityPhrase = [
opCount > 0 ? toolsPhrase : null,
triggerCount > 0 ? triggersPhrase : null,
Expand Down Expand Up @@ -274,11 +290,13 @@ function buildFAQs(integration: Integration, relatedNames: string[]): FAQItem[]
? [
{
question: `How do I trigger a Sim agent from ${name} automatically?`,
answer: `Add ${articleFor(name)} ${name} trigger block to your agent and copy its generated webhook URL into ${name}'s webhook settings. Sim supports ${triggersPhrase} for ${name}: ${triggerListPhrase}. Once configured, every matching ${name} event starts your agent instantly, no polling, no delay.`,
answer: triggersArePolling
? `Add ${articleFor(name)} ${name} trigger block to your agent and configure it to check ${name} on a schedule. Sim supports ${triggersPhrase} for ${name}: ${triggerListPhrase}. Once configured, your agent runs automatically whenever new data appears.`
: `Add ${articleFor(name)} ${name} trigger block to your agent and copy its generated webhook URL into ${name}'s webhook settings. Sim supports ${triggersPhrase} for ${name}: ${triggerListPhrase}. Once configured, every matching ${name} event starts your agent instantly, no polling, no delay.`,
Comment thread
waleedlatif1 marked this conversation as resolved.
},
{
question: `What data does Sim receive when a ${name} event triggers an agent?`,
answer: `Sim receives the full event payload ${name} sends, typically the record or object that changed, plus metadata like the event type and timestamp.${
answer: `Sim receives the full ${name} payload for the record or object that changed, plus metadata like the event type and timestamp, ${triggersArePolling ? `the next time ${name} is checked` : `delivered the instant ${name} sends it`}.${
firstTriggerWhen
? ` For example, the "${firstTrigger.name}" trigger fires ${sentenceWithTerminalPunctuation(firstTriggerWhen)}`
: ''
Expand Down Expand Up @@ -330,7 +348,12 @@ export async function generateMetadata({
...(opSample ? [`${name} ${opSample}`] : []),
`${categoryLabel} integration`,
...(integration.tags ?? []).map((tag) => `${name} ${tag.replace(/-/g, ' ')}`),
...(integration.triggerCount > 0 ? [`${name} webhook`, `${name} trigger`] : []),
...(integration.triggerCount > 0
? [
...(hasWebhookTrigger(integration.triggers) ? [`${name} webhook`] : []),
`${name} trigger`,
]
: []),
'AI workspace integrations',
'AI agent integrations',
'AI agent builder',
Expand Down Expand Up @@ -467,7 +490,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
? `${operations.length} ${name} tool${operations.length === 1 ? '' : 's'}`
: null,
triggers.length > 0
? `${triggers.length} real-time trigger${triggers.length === 1 ? '' : 's'}`
? `${triggers.length} ${triggerKindLabel(triggers)} trigger${triggers.length === 1 ? '' : 's'}`
: null,
]
.filter((part): part is string => part !== null)
Expand Down Expand Up @@ -678,12 +701,18 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
</h2>
</div>
<p className='text-[14px] text-[var(--text-body)] leading-[150%] tracking-[0.02em]'>
{seo?.triggersIntro ?? (
<>
Connect {articleFor(name)} {name} webhook to Sim and your agent runs the instant
an event happens, no polling, no delay.
</>
)}
{seo?.triggersIntro ??
(hasWebhookTrigger(triggers) ? (
<>
Connect {articleFor(name)} {name} webhook to Sim and your agent runs the
instant an event happens, no polling, no delay.
</>
) : (
<>
Sim checks {name} regularly and runs your agent automatically when new data
appears.
</>
))}
Comment thread
waleedlatif1 marked this conversation as resolved.
</p>
</div>
<div className='h-px w-full bg-[var(--border)]' />
Expand Down Expand Up @@ -913,7 +942,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
alt='Sim'
width={56}
height={56}
className='shrink-0 rounded-xl'
className='shrink-0 rounded-xl border border-[var(--border-1)]'
unoptimized
/>
<div className='flex items-center gap-2'>
Expand All @@ -940,7 +969,7 @@ export default async function IntegrationPage({ params }: { params: Promise<{ sl
bgColor={bgColor}
name={name}
Icon={IconComponent}
className='size-14 rounded-xl'
className='size-14 rounded-xl border border-[var(--border-1)]'
iconClassName='size-7'
fallbackClassName='text-[22px]'
aria-hidden='true'
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/(landing)/integrations/data/seo-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export const INTEGRATION_SEO: Record<string, IntegrationSeoContent> = {
overview:
'Integrate HubSpot into your workflow and run HubSpot automation inside Sim. Create, update, and manage CRM records, or trigger agents and workflows from HubSpot events. This HubSpot integration helps teams automate follow-ups, sync CRM data, and build faster HubSpot automation workflows from one AI workspace.',
triggersIntro:
'Connect a HubSpot webhook to Sim and trigger workflows the moment CRM activity happens. Run agents when records are created or updated, then automate routing, enrichment, follow-ups, and downstream actions without manual work.',
'Sim checks HubSpot on a schedule and runs agents when records are created or updated, so you can automate routing, enrichment, follow-ups, and downstream actions without manual work.',
},
notion: {
title: 'Notion Automation with Sim',
Expand Down
Loading
Loading