Implement the Meetlead widget
Configure a Website, embed the script and securely connect anonymous visits with signed-in customer accounts.
Quick start
Integrate in four steps
The shortest path from an empty configuration to a first test conversation.
- Create a Website in Settings and copy its unique public clientId.
- Add every exact allowed hostname. Add example.com and www.example.com separately; wildcards are not supported.
- Embed the script once in the shared page layout.
- Send a test message and confirm that the conversation appears in Meetlead Inbox.
<script
src="https://widget.meetlead.eu/widget.js"
data-client-id="YOUR_CLIENT_ID"
async
></script>Configuration
Configure the Website
A Website determines domains, appearance, rules and the data context for visitors.
Use a separate Website for every independent site or customer-data context. Never reuse another Website’s clientId: events and conversations would be assigned to the wrong context.
Add staging hostnames for testing and remove unused domains in production. Configure widget copy, work schedules, privacy policy and enabled applications before publishing.
Embedding
Install the widget
Place the asynchronous script in the document head or the shared application layout so it loads exactly once.
For WordPress, use the official plugin or add the snippet through a trusted header-code tool. For React, Vue and other SPAs, mount it in the root HTML rather than on every route change. For Next.js, use the shared App Router layout or Pages Router application shell.
After deployment, bypass the browser cache, verify widget.js in developer tools, open the launcher and send a test message. The public clientId is not a secret.
<script
src="https://widget.meetlead.eu/widget.js"
data-client-id="YOUR_CLIENT_ID"
async
></script>Customers
Connect a visit with a customer
Call meetlead.identify() after login with a stable userId. No identity secret or HMAC is required to assign the profile within one Website.
Read the profile from an authenticated backend endpoint with Cache-Control: no-store. Pass persisted userId and contact details to the widget; never trust an ID sent in a request body.
The onResult callback returns accepted, rejected or timeout with requestId, clientId and identityVerified. Store a local account marker only after a matching accepted result. accepted confirms profile assignment, not permission to read history. Earlier conversations require a verified session or signed identity. When email-code recovery is available for the Website, it requires a separate verification and grants access only to permitted threads; operator merging does not grant browser access.
Call logout on actual sign-out, account switch or session expiry. Retry transient network errors without logout and ignore late results from an earlier account. Profiles and permissions stay scoped to one Website. Existing signed integrations can still supply optional userHash; keep its HMAC secret exclusively on the backend.
// The endpoint requires an active user session.
// Do not use an identifier supplied in the request body.
response.setHeader('Cache-Control', 'no-store');
return {
userId: String(authenticatedUser.id),
email: authenticatedUser.email,
name: authenticatedUser.name
};(() => {
const identity = {
userId: currentUser.userId,
email: currentUser.email,
name: currentUser.name,
attributes: { plan: currentUser.plan }
};
const options = {
requestId: crypto.randomUUID(),
onResult(result) {
// accepted confirms profile attribution; it does not grant history access.
if (result.status === 'accepted') console.log('Profile attributed');
}
};
const meetlead = window.meetlead || (window.meetlead = { q: [] });
if (typeof meetlead.identify === 'function') {
meetlead.identify(identity, options);
} else {
meetlead.q.push(['identify', identity, options]);
}
})();(() => {
const meetlead = window.meetlead || (window.meetlead = { q: [] });
if (typeof meetlead.logout === 'function') {
meetlead.logout();
} else {
meetlead.q.push(['logout']);
}
})();Contexts
Use several Websites safely
Each Website has independent domains, widget settings and visitor data.
Teams and subscription may be shared across a Workspace, but requests, sockets and analytics always operate in the selected Website context. Use the matching clientId on each site and keep allowed-domain lists narrow.
When moving an installation, publish the new Website configuration and test it before removing the previous domain. Do not use one clientId as a shortcut for unrelated brands or tenants.
Measurement
Send goals and customer feedback
Use explicit events for outcomes that matter instead of inferring them from page views.
Create goal keys in the panel and send them only after the corresponding business action succeeds. Do not include sensitive personal content in names or metadata.
After a conversation, CSAT can record a rating and optional feedback according to your widget configuration and privacy notice.
// The goal must already exist and be active in Meetlead.
(() => {
const meetlead = window.meetlead || (window.meetlead = { q: [] });
const goalOptions = { value: 249, currency: 'PLN' };
if (typeof meetlead.goal === 'function') {
meetlead.goal('purchase', goalOptions);
} else {
meetlead.q.push(['goal', 'purchase', goalOptions]);
}
})();function submitMeetleadCsat(score, comment) {
const meetlead = window.meetlead || (window.meetlead = { q: [] });
if (typeof meetlead.csat === 'function') {
meetlead.csat(score, comment);
} else {
meetlead.q.push(['csat', score, comment]);
}
}
// Call only after the customer intentionally submits a rating from 1 to 5.
// submitMeetleadCsat(customerScore, customerComment);Production
Security, consent and Content Security Policy
Publish only after checking domains, privacy rules, masking and the production CSP.
- Allow the Meetlead API and widget origins required by the enabled features.
- Select the consent mode that matches your legal basis and CMP behavior.
- Mask or exclude inputs and content that must not enter recordings.
- Verify desktop and mobile launcher placement, offline forms and file uploads.
- Test sign-in identification and logout on a shared device.
- Confirm the first production conversation in the correct Website.
Diagnostics
Resolve common installation problems
Most failures are caused by a mismatched clientId, missing domain, duplicate script or blocking CSP.
If the launcher does not appear, check the Network and Console panels, confirm the exact hostname and make sure the widget is enabled. If conversations reach the wrong Website, remove the script immediately and replace its clientId.
When identification fails, check the stable userId, clientId and matching requestId in the acknowledgement. When consent blocks analytics, inspect the selected mode and the CMP signal before changing widget code.