Integrate CONSETO into React applications using hooks and context. Works with Next.js, Vite, Create React App, and other React frameworks.
Requires basic React knowledge. Works with any React-based framework.
In Next.js App Router, layout.tsx is a Server Component by default. Since event handlers like onLoad require client-side JavaScript, you need to create a separate Client Component.
Server Components cannot have event handlers. The onLoad callback ensures the SDK is fully loaded before initialization, preventing race conditions.
Step 1: Create the Client Component
// components/conseto-init.tsx
'use client'
import Script from 'next/script'
export function ConsetoInit() {
return (
<Script
src="https://www.conseto.io/dist/conseto.min.js"
strategy="afterInteractive"
onLoad={() => {
if (typeof window !== 'undefined' && window.Conseto) {
window.Conseto.init({
clientId: process.env.NEXT_PUBLIC_CONSETO_CLIENT_ID,
language: 'sk',
theme: 'auto'
}).then(conseto => {
window.conseto = conseto;
});
}
}}
/>
)
}Step 2: Add to your layout
// app/layout.tsx
import { ConsetoInit } from '@/components/conseto-init'
export default function RootLayout({ children }) {
return (
<html lang="sk">
<body>
{children}
<ConsetoInit />
</body>
</html>
)
}If you prefer not to create a separate component, you can use an inline script. This works directly in Server Components but is slightly less elegant:
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html lang="sk">
<body>
{children}
{/* Load SDK */}
<Script
src="https://www.conseto.io/dist/conseto.min.js"
strategy="afterInteractive"
/>
{/* Initialize after load */}
<Script id="conseto-init" strategy="lazyOnload">
{`
(function checkConseto() {
if (window.Conseto) {
window.Conseto.init({
clientId: '${process.env.NEXT_PUBLIC_CONSETO_CLIENT_ID}',
language: 'sk',
theme: 'auto'
});
} else {
setTimeout(checkConseto, 50);
}
})();
`}
</Script>
</body>
</html>
)
}Create a custom hook for CONSETO:
// hooks/useConseto.ts
import { useEffect, useState } from 'react'
interface ConsetoConfig {
clientId: string
language?: string
theme?: 'dark' | 'light'
ga4?: string
gtm?: string
autoTrackEcommerce?: boolean
}
export function useConseto(config: ConsetoConfig) {
const [conseto, setConseto] = useState<any>(null)
const [isReady, setIsReady] = useState(false)
useEffect(() => {
const script = document.createElement('script')
script.src = 'https://www.conseto.io/dist/conseto.min.js'
script.async = true
script.onload = async () => {
const instance = await (window as any).Conseto.init(config)
setConseto(instance)
setIsReady(true)
;(window as any).conseto = instance
}
document.head.appendChild(script)
return () => {
document.head.removeChild(script)
}
}, [])
const track = (eventName: string, data?: Record<string, any>) => {
if (conseto) {
conseto.track(eventName, data)
}
}
const trackConversion = (conversionType: string, data?: Record<string, any>) => {
if (conseto) {
conseto.trackConversion(conversionType, data)
}
}
return { conseto, isReady, track, trackConversion }
}// components/AddToCartButton.tsx
'use client'
import { useConseto } from '@/hooks/useConseto'
export function AddToCartButton({ product }) {
const { track, isReady } = useConseto({
clientId: process.env.NEXT_PUBLIC_CONSETO_CLIENT_ID!,
language: 'sk',
theme: 'dark'
})
const handleAddToCart = () => {
// Add to cart logic...
// Track the event
track('add_to_cart', {
item_id: product.id,
item_name: product.name,
price: product.price,
quantity: 1
})
}
return (
<button onClick={handleAddToCart}>
Add to Cart
</button>
)
}// context/ConsetoContext.tsx
'use client'
import { createContext, useContext, useEffect, useState, ReactNode } from 'react'
interface ConsetoContextType {
conseto: any
isReady: boolean
track: (event: string, data?: Record<string, any>) => void
trackConversion: (type: string, data?: Record<string, any>) => void
}
const ConsetoContext = createContext<ConsetoContextType | null>(null)
export function ConsetoProvider({
children,
clientId,
...config
}: { children: ReactNode; clientId: string; [key: string]: any }) {
const [conseto, setConseto] = useState<any>(null)
const [isReady, setIsReady] = useState(false)
useEffect(() => {
const script = document.createElement('script')
script.src = 'https://www.conseto.io/dist/conseto.min.js'
script.async = true
script.onload = async () => {
const instance = await (window as any).Conseto.init({
clientId,
...config
})
setConseto(instance)
setIsReady(true)
}
document.head.appendChild(script)
}, [clientId])
const track = (event: string, data?: Record<string, any>) => {
conseto?.track(event, data)
}
const trackConversion = (type: string, data?: Record<string, any>) => {
conseto?.trackConversion(type, data)
}
return (
<ConsetoContext.Provider value={{ conseto, isReady, track, trackConversion }}>
{children}
</ConsetoContext.Provider>
)
}
export function useConsetoContext() {
const context = useContext(ConsetoContext)
if (!context) {
throw new Error('useConsetoContext must be used within ConsetoProvider')
}
return context
}