2
0

(pixel) Add skip initialization option

This commit is contained in:
Baptiste Arnaud
2023-06-28 10:29:58 +02:00
parent 033f8f99dd
commit 50fcbfd95e
12 changed files with 822 additions and 276 deletions

View File

@ -5,6 +5,7 @@ import { TextLink } from '@/components/TextLink'
import { TextInput } from '@/components/inputs' import { TextInput } from '@/components/inputs'
import { CodeEditor } from '@/components/inputs/CodeEditor' import { CodeEditor } from '@/components/inputs/CodeEditor'
import { Select } from '@/components/inputs/Select' import { Select } from '@/components/inputs/Select'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { Stack, Text } from '@chakra-ui/react' import { Stack, Text } from '@chakra-ui/react'
import { isDefined, isEmpty } from '@typebot.io/lib' import { isDefined, isEmpty } from '@typebot.io/lib'
import { import {
@ -25,6 +26,12 @@ type Props = {
type Item = NonNullable<PixelBlock['options']['params']>[number] type Item = NonNullable<PixelBlock['options']['params']>[number]
export const PixelSettings = ({ options, onOptionsChange }: Props) => { export const PixelSettings = ({ options, onOptionsChange }: Props) => {
const updateIsInitSkipped = (isChecked: boolean) =>
onOptionsChange({
...options,
isInitSkip: isChecked,
})
const updatePixelId = (pixelId: string) => const updatePixelId = (pixelId: string) =>
onOptionsChange({ onOptionsChange({
...options, ...options,
@ -77,6 +84,12 @@ export const PixelSettings = ({ options, onOptionsChange }: Props) => {
withVariableButton={false} withVariableButton={false}
placeholder='Pixel ID (e.g. "123456789")' placeholder='Pixel ID (e.g. "123456789")'
/> />
<SwitchWithLabel
label={'Skip initialization'}
moreInfoContent="Check this if the bot is embedded in your website and the pixel is already initialized."
initialValue={options?.isInitSkip ?? false}
onCheckChange={updateIsInitSkipped}
/>
<SwitchWithRelatedSettings <SwitchWithRelatedSettings
label={'Track event'} label={'Track event'}
initialValue={isDefined(options?.params)} initialValue={isDefined(options?.params)}

View File

@ -8,10 +8,6 @@ The Google Analytics integration block allows you to track a Google Analytics ev
alt="Google Analytics block" alt="Google Analytics block"
/> />
:::note
This block is not executed in Preview mode. To test it, you need to launch the published bot.
:::
When your flow contains a Google Analytics block, under the hood it: When your flow contains a Google Analytics block, under the hood it:
- Initialize GA and track a "Page view" event on page load. - Initialize GA and track a "Page view" event on page load.

View File

@ -8,10 +8,6 @@ The Pixel integration block allows you to add a Meta pixel to your bot and track
alt="Pixel block" alt="Pixel block"
/> />
:::note
This block is not executed in Preview mode. To test it, you need to launch the published bot.
:::
When your flow contains a pixel block, under the hood it: When your flow contains a pixel block, under the hood it:
- Initialize the pixel and track "PageView" event on page load. - Initialize the pixel and track "PageView" event on page load.

View File

@ -37,7 +37,7 @@ You can tweak `3000` (3s) to your liking.
In the Metadata section, you can customize how the preview card will look if you share your bot URL on social media for example. In the Metadata section, you can customize how the preview card will look if you share your bot URL on social media for example.
You can also add some custom head code to add third-party scripts like a Facebook pixel for example. You can also add some custom head code to add third-party scripts.
### Google Tag Manager ### Google Tag Manager

View File

@ -184,6 +184,28 @@ typebot-bubble::part(preview-message) {
} }
``` ```
## Callbacks
If you need to trigger events on your parent website when the user interact with the bot, you can use the following callbacks:
```js
Typebot.initStandard({
typebot: 'my-typebot',
onNewInputBlock: (inputBlock) => {
console.log('New input block displayed', inputBlock.id)
},
onAnswer: (answer) => {
console.log('Answer received', answer.message, answer.blockId)
},
onInit: () => {
console.log('Bot initialized')
},
onEnd: () => {
console.log('Bot ended')
},
})
```
## Additional configuration ## Additional configuration
You can prefill the bot variable values in your embed code by adding the `prefilledVariables` option. Here is an example: You can prefill the bot variable values in your embed code by adding the `prefilledVariables` option. Here is an example:

View File

@ -3402,6 +3402,170 @@
"webhookId" "webhookId"
], ],
"additionalProperties": false "additionalProperties": false
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"groupId": {
"type": "string"
},
"outgoingEdgeId": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"Pixel"
]
},
"options": {
"anyOf": [
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"not": {}
}
},
"additionalProperties": false
},
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Lead",
"Contact",
"CompleteRegistration",
"Schedule",
"SubmitApplication",
"ViewContent",
"AddPaymentInfo",
"AddToCart",
"AddToWishlist",
"CustomizeProduct",
"Donate",
"FindLocation",
"InitiateCheckout",
"Purchase",
"Search",
"StartTrial",
"Subscribe"
]
}
},
"required": [
"eventType"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Custom"
]
},
"name": {
"type": "string"
}
},
"required": [
"eventType"
],
"additionalProperties": false
}
]
}
},
"required": [
"id",
"groupId",
"type",
"options"
],
"additionalProperties": false
} }
] ]
} }
@ -3568,6 +3732,9 @@
"schema": { "schema": {
"type": "object", "type": "object",
"properties": { "properties": {
"icon": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
} }

View File

@ -2996,6 +2996,170 @@
"webhookId" "webhookId"
], ],
"additionalProperties": false "additionalProperties": false
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"groupId": {
"type": "string"
},
"outgoingEdgeId": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"Pixel"
]
},
"options": {
"anyOf": [
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"not": {}
}
},
"additionalProperties": false
},
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Lead",
"Contact",
"CompleteRegistration",
"Schedule",
"SubmitApplication",
"ViewContent",
"AddPaymentInfo",
"AddToCart",
"AddToWishlist",
"CustomizeProduct",
"Donate",
"FindLocation",
"InitiateCheckout",
"Purchase",
"Search",
"StartTrial",
"Subscribe"
]
}
},
"required": [
"eventType"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Custom"
]
},
"name": {
"type": "string"
}
},
"required": [
"eventType"
],
"additionalProperties": false
}
]
}
},
"required": [
"id",
"groupId",
"type",
"options"
],
"additionalProperties": false
} }
] ]
} }
@ -4644,92 +4808,213 @@
{ {
"anyOf": [ "anyOf": [
{ {
"type": "object", "anyOf": [
"properties": { {
"scriptToExecute": { "anyOf": [
"type": "object", {
"properties": { "type": "object",
"content": { "properties": {
"type": "string" "scriptToExecute": {
}, "type": "object",
"args": { "properties": {
"type": "array", "content": {
"items": { "type": "string"
"type": "object", },
"properties": { "args": {
"id": { "type": "array",
"type": "string" "items": {
}, "type": "object",
"value": { "properties": {
"anyOf": [ "id": {
{ "type": "string"
"anyOf": [ },
{ "value": {
"anyOf": [ "anyOf": [
{ {
"type": "string" "anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
{
"type": "boolean"
}
]
}, },
{ {
"type": "number" "type": "array",
"items": {
"type": "string",
"nullable": true
}
} }
] ],
}, "nullable": true
{
"type": "boolean"
} }
] },
}, "required": [
{ "id"
"type": "array", ],
"items": { "additionalProperties": false
"type": "string",
"nullable": true
}
} }
], }
"nullable": true },
} "required": [
}, "content",
"required": [ "args"
"id" ],
], "additionalProperties": false
"additionalProperties": false }
} },
"required": [
"scriptToExecute"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"redirect": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"isNewTab": {
"type": "boolean"
}
},
"required": [
"isNewTab"
],
"additionalProperties": false
}
},
"required": [
"redirect"
],
"additionalProperties": false
}
]
},
{
"type": "object",
"properties": {
"chatwoot": {
"type": "object",
"properties": {
"scriptToExecute": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"args": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"value": {
"anyOf": [
{
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
{
"type": "boolean"
}
]
},
{
"type": "array",
"items": {
"type": "string",
"nullable": true
}
}
],
"nullable": true
}
},
"required": [
"id"
],
"additionalProperties": false
}
}
},
"required": [
"content",
"args"
],
"additionalProperties": false
}
},
"required": [
"scriptToExecute"
],
"additionalProperties": false
} }
}, },
"required": [ "required": [
"content", "chatwoot"
"args"
], ],
"additionalProperties": false "additionalProperties": false
} }
}, ]
"required": [
"scriptToExecute"
],
"additionalProperties": false
}, },
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"redirect": { "googleAnalytics": {
"type": "object", "type": "object",
"properties": { "properties": {
"url": { "trackingId": {
"type": "string" "type": "string"
}, },
"isNewTab": { "category": {
"type": "boolean" "type": "string"
},
"action": {
"type": "string"
},
"label": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "number"
},
{}
]
},
"sendTo": {
"type": "string"
} }
}, },
"required": [
"isNewTab"
],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"redirect" "googleAnalytics"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4738,75 +5023,21 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"chatwoot": { "wait": {
"type": "object", "type": "object",
"properties": { "properties": {
"scriptToExecute": { "secondsToWaitFor": {
"type": "object", "type": "number"
"properties": {
"content": {
"type": "string"
},
"args": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"value": {
"anyOf": [
{
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
{
"type": "boolean"
}
]
},
{
"type": "array",
"items": {
"type": "string",
"nullable": true
}
}
],
"nullable": true
}
},
"required": [
"id"
],
"additionalProperties": false
}
}
},
"required": [
"content",
"args"
],
"additionalProperties": false
} }
}, },
"required": [ "required": [
"scriptToExecute" "secondsToWaitFor"
], ],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"chatwoot" "wait"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4815,38 +5046,75 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"googleAnalytics": { "setVariable": {
"type": "object", "type": "object",
"properties": { "properties": {
"trackingId": { "scriptToExecute": {
"type": "string" "type": "object",
}, "properties": {
"category": { "content": {
"type": "string" "type": "string"
},
"action": {
"type": "string"
},
"label": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "number"
}, },
{} "args": {
] "type": "array",
}, "items": {
"sendTo": { "type": "object",
"type": "string" "properties": {
"id": {
"type": "string"
},
"value": {
"anyOf": [
{
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
{
"type": "boolean"
}
]
},
{
"type": "array",
"items": {
"type": "string",
"nullable": true
}
}
],
"nullable": true
}
},
"required": [
"id"
],
"additionalProperties": false
}
}
},
"required": [
"content",
"args"
],
"additionalProperties": false
} }
}, },
"required": [
"scriptToExecute"
],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"googleAnalytics" "setVariable"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4855,21 +5123,38 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"wait": { "streamOpenAiChatCompletion": {
"type": "object", "type": "object",
"properties": { "properties": {
"secondsToWaitFor": { "messages": {
"type": "number" "type": "array",
"items": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"role": {
"type": "string",
"enum": [
"system",
"user",
"assistant"
]
}
},
"additionalProperties": false
}
} }
}, },
"required": [ "required": [
"secondsToWaitFor" "messages"
], ],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"wait" "streamOpenAiChatCompletion"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4878,75 +5163,42 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"setVariable": { "webhookToExecute": {
"type": "object", "type": "object",
"properties": { "properties": {
"scriptToExecute": { "url": {
"type": "string"
},
"headers": {
"type": "object", "type": "object",
"properties": { "additionalProperties": {
"content": { "type": "string"
"type": "string" }
}, },
"args": { "body": {},
"type": "array", "method": {
"items": { "type": "string",
"type": "object", "enum": [
"properties": { "POST",
"id": { "GET",
"type": "string" "PUT",
}, "DELETE",
"value": { "PATCH",
"anyOf": [ "HEAD",
{ "CONNECT",
"anyOf": [ "OPTIONS",
{ "TRACE"
"anyOf": [ ]
{
"type": "string"
},
{
"type": "number"
}
]
},
{
"type": "boolean"
}
]
},
{
"type": "array",
"items": {
"type": "string",
"nullable": true
}
}
],
"nullable": true
}
},
"required": [
"id"
],
"additionalProperties": false
}
}
},
"required": [
"content",
"args"
],
"additionalProperties": false
} }
}, },
"required": [ "required": [
"scriptToExecute" "url"
], ],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"setVariable" "webhookToExecute"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4955,38 +5207,27 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"streamOpenAiChatCompletion": { "startPropsToInject": {
"type": "object", "type": "object",
"properties": { "properties": {
"messages": { "googleAnalyticsId": {
"type": "array", "type": "string"
"items": { },
"type": "object", "pixelId": {
"properties": { "type": "string"
"content": { },
"type": "string" "gtmId": {
}, "type": "string"
"role": { },
"type": "string", "customHeadCode": {
"enum": [ "type": "string"
"system",
"user",
"assistant"
]
}
},
"additionalProperties": false
}
} }
}, },
"required": [
"messages"
],
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": [ "required": [
"streamOpenAiChatCompletion" "startPropsToInject"
], ],
"additionalProperties": false "additionalProperties": false
} }
@ -4995,42 +5236,146 @@
{ {
"type": "object", "type": "object",
"properties": { "properties": {
"webhookToExecute": { "pixel": {
"type": "object", "anyOf": [
"properties": { {
"url": {
"type": "string"
},
"headers": {
"type": "object", "type": "object",
"additionalProperties": { "properties": {
"type": "string" "pixelId": {
} "type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"not": {}
}
},
"additionalProperties": false
}, },
"body": {}, {
"method": { "type": "object",
"type": "string", "properties": {
"enum": [ "pixelId": {
"POST", "type": "string"
"GET", },
"PUT", "isInitSkip": {
"DELETE", "type": "boolean"
"PATCH", },
"HEAD", "params": {
"CONNECT", "type": "array",
"OPTIONS", "items": {
"TRACE" "type": "object",
] "properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Lead",
"Contact",
"CompleteRegistration",
"Schedule",
"SubmitApplication",
"ViewContent",
"AddPaymentInfo",
"AddToCart",
"AddToWishlist",
"CustomizeProduct",
"Donate",
"FindLocation",
"InitiateCheckout",
"Purchase",
"Search",
"StartTrial",
"Subscribe"
]
}
},
"required": [
"eventType"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"pixelId": {
"type": "string"
},
"isInitSkip": {
"type": "boolean"
},
"params": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"value": {}
},
"required": [
"id"
],
"additionalProperties": false
}
},
"eventType": {
"type": "string",
"enum": [
"Custom"
]
},
"name": {
"type": "string"
}
},
"required": [
"eventType"
],
"additionalProperties": false
} }
}, ]
"required": [
"url"
],
"additionalProperties": false
} }
}, },
"required": [ "required": [
"webhookToExecute" "pixel"
], ],
"additionalProperties": false "additionalProperties": false
} }

View File

@ -6,7 +6,8 @@ export const executePixelBlock = (
{ typebot: { variables }, result }: SessionState, { typebot: { variables }, result }: SessionState,
block: PixelBlock block: PixelBlock
): ExecuteIntegrationResponse => { ): ExecuteIntegrationResponse => {
if (!result) return { outgoingEdgeId: block.outgoingEdgeId } if (!result || !block.options.pixelId || !block.options.eventType)
return { outgoingEdgeId: block.outgoingEdgeId }
const pixel = deepParseVariables(variables, { const pixel = deepParseVariables(variables, {
guessCorrectTypes: true, guessCorrectTypes: true,
removeEmptyStrings: true, removeEmptyStrings: true,

View File

@ -455,7 +455,9 @@ const parseStartClientSideAction = (
pixelId: ( pixelId: (
blocks.find( blocks.find(
(block) => (block) =>
block.type === IntegrationBlockType.PIXEL && block.options.pixelId block.type === IntegrationBlockType.PIXEL &&
block.options.pixelId &&
block.options.isInitSkip !== true
) as PixelBlock | undefined ) as PixelBlock | undefined
)?.options.pixelId, )?.options.pixelId,
} }

View File

@ -1,4 +1,4 @@
import { isEmpty } from '@typebot.io/lib/utils' import { isDefined, isEmpty } from '@typebot.io/lib/utils'
import type { GoogleAnalyticsOptions } from '@typebot.io/schemas' import type { GoogleAnalyticsOptions } from '@typebot.io/schemas'
declare const gtag: ( declare const gtag: (
@ -12,8 +12,9 @@ declare const gtag: (
} }
) => void ) => void
export const initGoogleAnalytics = (id: string): Promise<void> => export const initGoogleAnalytics = (id: string): Promise<void> => {
new Promise((resolve) => { if (isDefined(gtag)) return Promise.resolve()
return new Promise((resolve) => {
const existingScript = document.getElementById('gtag') const existingScript = document.getElementById('gtag')
if (!existingScript) { if (!existingScript) {
const script = document.createElement('script') const script = document.createElement('script')
@ -34,6 +35,7 @@ export const initGoogleAnalytics = (id: string): Promise<void> =>
} }
if (existingScript) resolve() if (existingScript) resolve()
}) })
}
export const sendGaEvent = (options: GoogleAnalyticsOptions) => { export const sendGaEvent = (options: GoogleAnalyticsOptions) => {
if (!options) return if (!options) return

View File

@ -3,7 +3,8 @@ import { PixelBlock } from '@typebot.io/schemas'
declare const fbq: ( declare const fbq: (
arg0: string, arg0: string,
arg1: string, arg1: string,
arg2: Record<string, string> | undefined arg2: string,
arg3: Record<string, string> | undefined
) => void ) => void
export const initPixel = (pixelId: string) => { export const initPixel = (pixelId: string) => {
@ -26,7 +27,7 @@ export const initPixel = (pixelId: string) => {
} }
export const trackPixelEvent = (options: PixelBlock['options']) => { export const trackPixelEvent = (options: PixelBlock['options']) => {
if (!options.eventType) return if (!options.eventType || !options.pixelId) return
const params = options.params?.length const params = options.params?.length
? options.params.reduce<Record<string, string>>((obj, param) => { ? options.params.reduce<Record<string, string>>((obj, param) => {
if (!param.key || !param.value) return obj if (!param.key || !param.value) return obj
@ -35,7 +36,7 @@ export const trackPixelEvent = (options: PixelBlock['options']) => {
: undefined : undefined
if (options.eventType === 'Custom') { if (options.eventType === 'Custom') {
if (!options.name) return if (!options.name) return
fbq('trackCustom', options.name, params) fbq('trackCustom', options.pixelId, options.name, params)
} }
fbq('track', options.eventType, params) fbq('track', options.pixelId, options.eventType, params)
} }

View File

@ -5,6 +5,7 @@ import { IntegrationBlockType } from '../enums'
const basePixelOptionSchema = z.object({ const basePixelOptionSchema = z.object({
pixelId: z.string().optional(), pixelId: z.string().optional(),
isInitSkip: z.boolean().optional(),
params: z params: z
.array( .array(
z.object({ z.object({