Learn how to integrate Entri into your React application with proper event handling and state management.
Prerequisites
- Your
applicationId from the Entri dashboard
- A valid JWT token fetched from your server
- Basic understanding of React hooks
Installation
Import the functions you need:import { showEntri, close, checkDomain } from 'entrijs';
NPM functions are async - the package automatically loads the Entri SDK when first called.
Quick Start (NPM)
import { useEffect } from 'react';
import { showEntri } from 'entrijs';
function DomainConnect({ applicationId, token }) {
useEffect(() => {
const handleClose = (event) => {
console.log('Entri closed:', event.detail);
};
window.addEventListener('onEntriClose', handleClose);
return () => window.removeEventListener('onEntriClose', handleClose);
}, []);
const handleConnect = async () => {
await showEntri({
applicationId,
token,
dnsRecords: [
{
type: 'CNAME',
host: 'www',
value: 'your-service.com',
ttl: 300,
},
],
});
};
return <button onClick={handleConnect}>Connect Domain</button>;
}
Custom Hook (NPM)
// hooks/useEntri.js
import { useState, useEffect, useCallback } from 'react';
import { showEntri, close } from 'entrijs';
export function useEntri() {
const [isOpen, setIsOpen] = useState(false);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const handleSuccess = (event) => {
setResult(event.detail);
};
const handleClose = (event) => {
setIsOpen(false);
if (event.detail?.error) {
setError(event.detail.error);
}
};
window.addEventListener('onSuccess', handleSuccess);
window.addEventListener('onEntriClose', handleClose);
return () => {
window.removeEventListener('onSuccess', handleSuccess);
window.removeEventListener('onEntriClose', handleClose);
};
}, []);
const openEntri = useCallback(async (config) => {
setIsOpen(true);
setError(null);
setResult(null);
await showEntri({
applicationId: config.applicationId,
token: config.token,
dnsRecords: config.dnsRecords,
prefilledDomain: config.prefilledDomain,
userId: config.userId,
});
}, []);
const closeEntri = useCallback(async () => {
await close();
}, []);
return {
openEntri,
closeEntri,
isOpen,
result,
error,
};
}
With TypeScript (NPM)
The package exports types you can use:import {
showEntri,
close,
type EntriConfig,
type EntriCloseEventDetail,
type EntriSuccessEventDetail,
} from 'entrijs';
Add to your index.html:<script src="https://cdn.goentri.com/entri.js"></script>
The SDK will be available globally as window.entri.Quick Start (Script Tag)
import { useEffect } from 'react';
function DomainConnect({ applicationId, token }) {
useEffect(() => {
const handleClose = (event) => {
console.log('Entri closed:', event.detail);
};
window.addEventListener('onEntriClose', handleClose);
return () => window.removeEventListener('onEntriClose', handleClose);
}, []);
const handleConnect = () => {
window.entri.showEntri({
applicationId,
token,
dnsRecords: [
{
type: 'CNAME',
host: 'www',
value: 'your-service.com',
ttl: 300,
},
],
});
};
return <button onClick={handleConnect}>Connect Domain</button>;
}
Custom Hook (Script Tag)
// hooks/useEntri.js
import { useState, useEffect, useCallback } from 'react';
export function useEntri() {
const [isOpen, setIsOpen] = useState(false);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const handleSuccess = (event) => {
setResult(event.detail);
};
const handleClose = (event) => {
setIsOpen(false);
if (event.detail?.error) {
setError(event.detail.error);
}
};
window.addEventListener('onSuccess', handleSuccess);
window.addEventListener('onEntriClose', handleClose);
return () => {
window.removeEventListener('onSuccess', handleSuccess);
window.removeEventListener('onEntriClose', handleClose);
};
}, []);
const openEntri = useCallback((config) => {
setIsOpen(true);
setError(null);
setResult(null);
window.entri.showEntri({
applicationId: config.applicationId,
token: config.token,
dnsRecords: config.dnsRecords,
prefilledDomain: config.prefilledDomain,
userId: config.userId,
});
}, []);
const closeEntri = useCallback(() => {
window.entri.close();
}, []);
return {
openEntri,
closeEntri,
isOpen,
result,
error,
};
}
With TypeScript (Script Tag)
Define your own types or use the ones from the NPM package:interface EntriConfig {
applicationId: string;
token: string;
dnsRecords: DNSRecord[];
prefilledDomain?: string;
userId?: string;
}
interface DNSRecord {
type: 'A' | 'AAAA' | 'CNAME' | 'TXT' | 'MX' | 'NS';
host: string;
value: string;
ttl: number;
priority?: number;
}
interface EntriCloseEventDetail {
domain: string | null;
success: boolean;
setupType: 'automatic' | 'manual' | 'sharedLogin' | 'purchase' | null;
provider: string;
lastStatus: string;
error?: {
code: string;
title: string;
details: string;
};
}
interface EntriSuccessEventDetail {
domain: string;
success: true;
setupType: 'automatic' | 'manual';
provider: string;
jobId: string;
}
// Extend Window type
declare global {
interface Window {
entri: {
showEntri: (config: EntriConfig) => void;
close: () => void;
checkDomain: (domain: string, config: EntriConfig) => Promise<any>;
};
}
}
Using the Hook
Once you have the hook, use it in your components:
// components/DomainSetup.jsx
import { useEntri } from '../hooks/useEntri';
export function DomainSetup({ applicationId, token, userId }) {
const { openEntri, isOpen, result, error } = useEntri();
const handleConnect = () => {
openEntri({
applicationId,
token,
userId,
dnsRecords: [
{
type: 'CNAME',
host: 'www',
value: 'your-service.com',
ttl: 300,
},
],
});
};
if (result?.success) {
return (
<div className="success">
Domain {result.domain} connected successfully!
</div>
);
}
return (
<div>
<button onClick={handleConnect} disabled={isOpen}>
{isOpen ? 'Connecting...' : 'Connect Domain'}
</button>
{error && (
<p className="error">
Error: {error.title || 'An error occurred'}
</p>
)}
</div>
);
}
Event Handling
Entri emits events via window. Set up listeners in useEffect before calling showEntri().
Events work the same way for both NPM and Script Tag installations.
onSuccess
Triggered when the user successfully completes domain setup.
useEffect(() => {
const handleSuccess = (event) => {
const { domain, setupType, provider, jobId } = event.detail;
console.log(`Domain ${domain} configured via ${setupType}`);
// Store jobId for webhook correlation
};
window.addEventListener('onSuccess', handleSuccess);
return () => window.removeEventListener('onSuccess', handleSuccess);
}, []);
onEntriClose
Triggered when the modal is closed, whether successful or not.
useEffect(() => {
const handleClose = (event) => {
const { domain, success, setupType, lastStatus, error } = event.detail;
if (success) {
console.log(`${domain} configured successfully`);
} else if (error) {
console.log(`Error: ${error.code} - ${error.title}`);
} else {
console.log(`User exited at: ${lastStatus}`);
}
};
window.addEventListener('onEntriClose', handleClose);
return () => window.removeEventListener('onEntriClose', handleClose);
}, []);
onEntriStepChange
Triggered when the user moves between screens. Useful for analytics.
useEffect(() => {
const handleStepChange = (event) => {
const { step, domain, provider } = event.detail;
analytics.track('entri_step', { step, domain, provider });
};
window.addEventListener('onEntriStepChange', handleStepChange);
return () => window.removeEventListener('onEntriStepChange', handleStepChange);
}, []);
onEntriManualSetupDocumentationClick
Triggered when the user clicks the manual setup guide link.
useEffect(() => {
const handleManualClick = () => {
openSupportChat();
};
window.addEventListener('onEntriManualSetupDocumentationClick', handleManualClick);
return () => window.removeEventListener('onEntriManualSetupDocumentationClick', handleManualClick);
}, []);
Troubleshooting
Event listeners not firing
Make sure you’re adding listeners before calling showEntri(). In React, use useEffect to set up listeners on mount:
// ✅ Correct - listeners added on mount via useEffect
useEffect(() => {
window.addEventListener('onEntriClose', handler);
return () => window.removeEventListener('onEntriClose', handler);
}, []);
// ❌ Wrong - listener added after showEntri
const handleClick = () => {
showEntri(config); // or window.entri.showEntri(config)
window.addEventListener('onEntriClose', handler); // Too late!
};
Stale state in event handlers
React’s closures can capture stale state. Use refs or functional updates:
// ✅ Use functional update to avoid stale state
setResult(prevResult => ({
...prevResult,
...event.detail
}));
// ✅ Or use a ref for values needed in event handlers
const configRef = useRef(config);
useEffect(() => {
configRef.current = config;
}, [config]);
Multiple event handlers firing
Ensure you clean up listeners when the component unmounts:
useEffect(() => {
const handler = (event) => { /* ... */ };
window.addEventListener('onEntriClose', handler);
return () => {
window.removeEventListener('onEntriClose', handler);
};
}, []);
Next Steps