Build with Nuria
Embed live chat, surveys, and forms on your website. Connect via webhooks, authenticate with SSO, and integrate through our REST API.
Widget
Add live chat, surveys, and forms to your site with one script tag.
JavaScript API
Control the widget programmatically with window.Nuria.
Webhooks
Get real-time notifications for conversations, messages, and CSAT.
REST API
Manage contacts, conversations, tickets, and more via HTTP.
Quick Start
Get the Nuria widget running on your website in under 5 minutes.
-
Create your account
Sign up at app.nuria.run and create your workspace. -
Add a Web Chat channel
Go to Settings → Channels → Add Channel → Web Chat. Configure your welcome message, colors, and operating hours. -
Copy the embed code
After saving the channel, copy the script tag provided in the installation panel. -
Paste on your site
Add the script before the closing</body>tag on every page where you want the widget.
<!-- Nuria Widget -->
<script src="https://widget.nuria.run/loader.js" ws="YOUR_WORKSPACE_ID"></script>
09005ea904334c3fb61e2a8302a5f798.Widget Installation
Multiple ways to add Nuria to your website or application.
HTML / Script Tag
The simplest method. Add the loader script before the closing </body> tag:
<script src="https://widget.nuria.run/loader.js" ws="YOUR_WORKSPACE_ID"></script>
Attributes
| Attribute | Required | Description |
|---|---|---|
ws | Yes | Workspace ID. Determines which channels and rules to load. |
kb | No | Knowledge base ID. Scopes the chat to a specific KB. |
WordPress
Paste the same script tag into one of these locations:
- A Custom HTML block in your page/post editor
- Your theme's
footer.phpfile, before</body> - A Google Tag Manager Custom HTML tag
- A plugin like Insert Headers and Footers
React / Next.js
Load the script dynamically in a useEffect hook:
Reactimport { useEffect } from 'react';
function App() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://widget.nuria.run/loader.js';
script.setAttribute('ws', 'YOUR_WORKSPACE_ID');
document.body.appendChild(script);
return () => {
script.remove();
};
}, []);
return <div>My App</div>;
}
For Next.js App Router, use the script in a Client Component or via next/script:
Next.jsimport Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Script
src="https://widget.nuria.run/loader.js"
strategy="afterInteractive"
ws="YOUR_WORKSPACE_ID"
/>
</body>
</html>
);
}
Vue.js
Inject the script in your App.vue or main layout component:
Vue 3<script setup>
import { onMounted, onUnmounted } from 'vue';
let script;
onMounted(() => {
script = document.createElement('script');
script.src = 'https://widget.nuria.run/loader.js';
script.setAttribute('ws', 'YOUR_WORKSPACE_ID');
document.body.appendChild(script);
});
onUnmounted(() => {
script?.remove();
});
</script>
Display Rules
Channels support server-configured display rules evaluated client-side. Configure these in the Nuria dashboard, not via the JavaScript API.
| Rule | Options | Example |
|---|---|---|
| Where | URL include/exclude patterns with wildcard | /pricing* |
| When | Delay, scroll depth, exit intent, min visits | Show after 10 seconds |
| Who | Device type, identified vs anonymous, custom props | Desktop only, plan = pro |
JavaScript API
Once the loader runs, it exposes a global window.Nuria object. Use it to control the widget, identify visitors, and listen for events.
Nuria.isReady
boolean — true after the workspace config has been fetched, display rules evaluated, and active channels rendered.
if (window.Nuria.isReady) {
window.Nuria.chat.open();
}
Nuria.identify(user)
Identify the current visitor. This re-evaluates display rules and associates the conversation with a contact record.
window.Nuria.identify({
email: 'maria@acme.com',
name: 'Maria Silva',
phone: '+5511999999999',
// Custom properties (used in display rules and agent context)
plan: 'enterprise',
company: 'Acme Corp',
});
| Field | Type | Description |
|---|---|---|
email | string | Contact email for matching. |
name | string | Display name. |
phone | string | Phone number (E.164 recommended). |
* | any | Additional key-value pairs stored as custom data. |
Nuria.chat
Controls for the chat channel.
// Open / close / toggle the chat panel
window.Nuria.chat.open();
window.Nuria.chat.close();
window.Nuria.chat.toggle();
// Send a message programmatically
window.Nuria.chat.sendMessage('I need help with my order');
// Listen for incoming messages
window.Nuria.chat.onMessage((msg) => {
console.log('New message:', msg);
});
| Method | Description |
|---|---|
open() | Open the chat panel. |
close() | Close the chat panel. |
toggle() | Toggle open/closed. |
sendMessage(text) | Send a plain-text message as the visitor. |
onMessage(callback) | Shorthand for Nuria.on('message:received', cb). |
Nuria.survey
Controls for the survey channel.
window.Nuria.survey.show();
window.Nuria.survey.hide();
| Method | Description |
|---|---|
show() | Display the survey overlay. |
hide() | Dismiss the survey overlay. |
Nuria.form
Controls for the form channel.
window.Nuria.form.show();
window.Nuria.form.hide();
| Method | Description |
|---|---|
show() | Display the form overlay. |
hide() | Dismiss the form overlay. |
Events
Subscribe to widget events with Nuria.on(event, callback).
window.Nuria.on('ready', () => {
console.log('Widget loaded');
});
| Event | Callback Arguments | Description |
|---|---|---|
ready | (none) | Widget finished initializing. |
channel:show | channelId, type | A channel (chat/survey/form) became visible. |
channel:hide | channelId, type | A channel was hidden. |
message:received | message | A new message arrived in the chat. |
survey:submitted | response | Visitor submitted a survey response. |
identify | user | identify() was called. |
page:change | url | SPA navigation detected. |
Examples
Open chat on button click
<button onclick="window.Nuria.chat.open()">Talk to us</button>
Identify visitor after login
window.Nuria.on('ready', () => {
const user = getCurrentUser();
window.Nuria.identify({
email: user.email,
name: user.name,
plan: user.subscription,
});
});
Open chat with a pre-filled message
function askAboutPricing() {
window.Nuria.chat.open();
window.Nuria.chat.sendMessage('I would like to know about pricing');
}
Track messages in analytics
window.Nuria.on('message:received', (msg) => {
gtag('event', 'nuria_message_received', {
event_category: 'chat',
});
});
Show survey after 60 seconds
window.Nuria.on('ready', () => {
setTimeout(() => {
window.Nuria.survey.show();
}, 60000);
});
Custom trigger for the form
<a href="#" onclick="event.preventDefault(); window.Nuria.form.show();">
Open contact form
</a>
Webhook Events
Receive real-time HTTP POST notifications when events occur in your Nuria workspace.
Setup
Configure your webhook endpoint in Settings → Developers → Webhooks. Each webhook receives a JSON payload with a signature header for verification.
2xx status within 10 seconds. Failed deliveries are retried with exponential backoff (3 attempts).HMAC Verification
Every webhook includes a X-Nuria-Signature header containing an HMAC-SHA256 signature of the raw request body. Verify it using your webhook secret:
Node.jsimport crypto from 'crypto';
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express example
app.post('/webhooks/nuria', (req, res) => {
const signature = req.headers['x-nuria-signature'];
const rawBody = req.body; // raw string/buffer
if (!verifyWebhook(rawBody, signature, process.env.NURIA_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(rawBody);
console.log('Event:', event.type);
res.status(200).send('OK');
});
Event Reference
| Event | Description | Key Payload Fields |
|---|---|---|
conversation.created |
A new conversation was started. | conversation_id, channel, contact |
conversation.resolved |
A conversation was marked as resolved. | conversation_id, resolved_by, duration |
message.created |
A new message was sent (by visitor or agent). | message_id, conversation_id, sender, content |
agent.assigned |
An agent was assigned to a conversation. | conversation_id, agent_id, agent_name |
csat.submitted |
A customer satisfaction rating was submitted. | conversation_id, score, comment |
contact.created |
A new contact was created. | contact_id, email, name |
contact.updated |
A contact's information was updated. | contact_id, changes |
ticket.created |
A helpdesk ticket was created. | ticket_id, subject, priority, requester |
ticket.resolved |
A helpdesk ticket was resolved. | ticket_id, resolved_by |
Example Payload
{
"id": "evt_01JQXYZ...",
"type": "message.created",
"workspace_id": "09005ea9...",
"created_at": "2026-03-22T14:30:00Z",
"data": {
"message_id": "msg_01JQXYZ...",
"conversation_id": "conv_01JQXYZ...",
"sender": {
"type": "contact",
"id": "ct_01JQXYZ...",
"name": "Maria Silva"
},
"content": "I need help with my subscription",
"channel": "web_chat"
}
}
SSO Setup
Enable Single Sign-On for your workspace using OIDC or SAML 2.0. Available on Pro and Enterprise plans.
OpenID Connect (OIDC)
Supports Okta, Azure AD, Google Workspace, Auth0, and any OIDC-compliant provider.
-
Create an application in your IdP
Set the redirect URI tohttps://auth.api.nuria.run/sso/oidc/callback -
Collect your credentials
You will need the Client ID, Client Secret, and the Issuer URL (e.g.,https://login.microsoftonline.com/{tenant}/v2.0). -
Configure in Nuria
Go to Settings → Security → SSO. Select OIDC, paste your credentials, and save. -
Test the connection
Click Test SSO to verify. A successful test will show the authenticated user's email and name.
Provider-Specific Notes
| Provider | Issuer URL | Notes |
|---|---|---|
| Okta | https://{domain}.okta.com |
Use "Web Application" type. Enable openid, profile, email scopes. |
| Azure AD | https://login.microsoftonline.com/{tenant}/v2.0 |
Register app in "App registrations". Add User.Read permission. |
| Google Workspace | https://accounts.google.com |
Create OAuth2 credentials in Google Cloud Console. |
| Auth0 | https://{domain}.auth0.com/ |
Create a "Regular Web Application". |
SAML 2.0
For enterprise identity providers that require SAML (e.g., ADFS, Ping Identity).
-
Download Nuria's SP metadata
Available athttps://auth.api.nuria.run/sso/saml/metadata -
Register Nuria in your IdP
Import the SP metadata or manually configure:
ACS URL:https://auth.api.nuria.run/sso/saml/acs
Entity ID:https://auth.api.nuria.run
Name ID:emailAddress -
Upload IdP metadata to Nuria
Go to Settings → Security → SSO. Select SAML 2.0 and upload your IdP metadata XML. -
Map attributes
Ensure these SAML attributes are included in assertions:
| Nuria Field | SAML Attribute |
|---|---|
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress | |
| First Name | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname |
| Last Name | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname |
REST API
The Nuria REST API lets you programmatically manage contacts, conversations, tickets, and more. Base URL: https://api.nuria.run
Authentication
All API requests require authentication via one of these methods:
JWT Bearer Token
Obtain a token via the login endpoint or SSO flow. Include it in the Authorization header:
curl -X GET https://api.nuria.run/contacts \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json"
API Key
Create API keys in Settings → Developers → API Keys. Keys can be scoped to specific permissions (e.g., contacts:read, tickets:write).
curl -X GET https://api.nuria.run/contacts \
-H "X-API-Key: nuria_sk_live_..." \
-H "Content-Type: application/json"
Standard Headers
| Header | Description |
|---|---|
x-nuria-request-id | Unique request ID (auto-generated if not provided). |
x-nuria-tenant-id | Workspace ID (resolved from auth token). |
Rate Limits
Rate limits are enforced per-token with different tiers based on the endpoint:
| Tier | Free | Essential | Pro | Enterprise |
|---|---|---|---|---|
| Auth | 10/min | 20/min | 50/min | 250/min |
| API | 100/min | 200/min | 500/min | 2,500/min |
| Upload | 20/min | 40/min | 100/min | 500/min |
| Search | 30/min | 60/min | 150/min | 750/min |
Rate limit status is returned in response headers:
X-RateLimit-Plan: pro
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487