Widget Documentation
Guia completo para integrar o widget de suporte PumaHelp em sua aplicação.
🚀 Início Rápido
Instalação
Adicione o script do widget ao seu HTML:
<script src="https://cdn.pumahelp.com/widget-v2.1.0/widget.js" type="module"></script>
Uso Básico
Opção 1: Web Component (HTML)
<puma-help-widget
app-name="seu-subdominio"
api-key="key-xxxxxxxxxxxxx"
></puma-help-widget>
Opção 2: API JavaScript
const widget = window.PumaHelp.init({
appName: 'seu-subdominio',
apiKey: 'key-xxxxxxxxxxxxx'
});
⚙️ Configuração
Parâmetros Obrigatórios
| Parâmetro | Tipo | Descrição |
|---|---|---|
appName | string | Seu subdomínio PumaHelp (ex: minha-empresa) |
apiKey | string | Sua chave de API (começa com rk_live_) |
Segurança da API Key: Para uso no widget frontend, crie uma chave restrita no dashboard do PumaHelp com apenas a permissão "Criar Convidado (Guest)". Nunca use chaves com permissões administrativas no código client-side, pois elas ficam expostas no navegador.
Parâmetros Opcionais
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
theme | 'light' | 'dark' | 'dark' | Esquema de cores do widget |
language | 'pt-BR' | 'en' | 'pt-BR' | Idioma da interface |
color | string | - | Cor primária (formato hex: #FF6B35) |
icon | Tipo do ícone | 'puma' | Ícone do botão do widget |
soundEnabled | boolean | true | Habilitar sons de notificação |
debug | boolean | false | Habilitar logs de debug |
translations | string (JSON) | - | Textos personalizados |
Ícones disponíveis: 'puma', 'emoji', 'question', 'lines', 'bell', 'send'
Personalização de Textos
Você pode personalizar todos os textos estáticos do widget usando o atributo ou propriedade translations (string JSON).
Chaves disponíveis:
| Chave | Padrão (pt-BR / en) | Descrição |
|---|---|---|
mainTitle | Suporte | O título principal do widget (cabeçalho) |
welcome | Olá! 👋 / Hello! 👋 | Saudação no formulário de novo ticket |
description | Como podemos... | Descrição no formulário de novo ticket |
startNewChat | Nova Conversa / New Conversation | Texto do botão para iniciar chat |
sendMessage | Digite uma mensagem... | Placeholder para campos de mensagem |
loading | Carregando... | Texto de estado de carregamento |
endTicket | O atendimento foi finalizado. | Mensagem quando o ticket é fechado |
startedAt | Iniciado em / Started at | Texto do cabeçalho na visualização do chat (seguido da data) |
Exemplos
Tema escuro com cor personalizada:
window.PumaHelp.init({
appName: 'acme',
apiKey: 'key-abc123',
theme: 'dark',
color: '#2563eb',
language: 'en',
translations: {
mainTitle: 'Central de Ajuda',
welcome: 'Olá!',
sendMessage: 'Digite aqui...'
}
});
<puma-help-widget
app-name="acme"
api-key="key-abc123"
theme="light"
language="pt-BR"
color="#ff6b35"
icon="question"
translations='{
"mainTitle": "Central de Ajuda",
"welcome": "Olá!",
"sendMessage": "Digite aqui..."
}'
></puma-help-widget>
🛡️ Segurança e Boas Práticas
API Key Restrita
O widget é executado no navegador do usuário (client-side), portanto a apiKey fica visível no código-fonte da página. Para proteger seu sistema:
✅ O que fazer:
- Crie uma chave restrita no dashboard do PumaHelp
- Configure apenas a permissão:
Criar Convidado (Guest) - Use essa chave no widget
<!-- ✅ Correto: Chave restrita para widget -->
<puma-help-widget
app-name="minha-empresa"
api-key="rk_live_abc123xyz" <!-- Apenas permissão Guest -->
></puma-help-widget>
❌ O que NÃO fazer:
- ❌ Nunca use chaves com permissões administrativas no widget
- ❌ Nunca use chaves que podem:
- Deletar tickets
- Modificar configurações
- Acessar dados de outros usuários
- Executar operações privilegiadas
📘 Tipagem TypeScript
Para projetos TypeScript, crie o arquivo puma-widget.d.ts na raiz do seu projeto (ou em src/types/):
Arquivo de Tipos (puma-widget.d.ts)
import * as React from 'react';
// Atributos do Widget
interface PumaWidgetAttributes {
'app-name'?: string;
'api-key'?: string;
theme?: 'light' | 'dark';
language?: 'pt-BR' | 'en';
color?: string;
icon?: 'puma' | 'emoji' | 'question' | 'lines' | 'bell' | 'send';
'sound-enabled'?: string;
debug?: string;
translations?: string;
class?: string;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}
// Configuração do Widget
interface WidgetConfig {
appName: string;
apiKey: string;
theme?: 'light' | 'dark';
language?: 'pt-BR' | 'en';
color?: string;
icon?: 'puma' | 'emoji' | 'question' | 'lines' | 'bell' | 'send';
soundEnabled?: boolean;
debug?: boolean;
translations?: Translations;
}
// Traduções Customizáveis
interface Translations {
mainTitle?: string;
welcome?: string;
description?: string;
startNewChat?: string;
sendMessage?: string;
loading?: string;
endTicket?: string;
startedAt?: string;
[key: string]: string | undefined;
}
// Identidade do Usuário
interface UserIdentity {
accessToken: string;
name?: string;
}
// Instância do Widget
interface WidgetInstance {
id: string;
element: HTMLElement;
isOpen: boolean;
isHidden: boolean;
open(): void;
close(): void;
toggle(): void;
hide(): void;
show(): void;
destroy(): void;
identify(identity: UserIdentity): void;
logout(): void;
on(event: string, callback: (event: CustomEvent) => void): () => void;
}
// API Global
interface PumaHelpAPI {
init(config: WidgetConfig & { container?: HTMLElement }): WidgetInstance;
destroy(instanceId: string): boolean;
getInstances(): WidgetInstance[];
destroyAll(): void;
identify(identity: UserIdentity): void;
logout(): void;
}
// Declaração Global
declare global {
interface Window {
PumaHelp: PumaHelpAPI;
}
// Registro do Custom Element (DOM)
interface HTMLElementTagNameMap {
'puma-help-widget': HTMLElement & {
open(): void;
close(): void;
toggle(): void;
hide(): void;
show(): void;
destroy(): void;
};
}
}
// Declaração JSX para React/Next.js (React 18+)
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'puma-help-widget': PumaWidgetAttributes;
}
}
}
export {};
Uso em TypeScript
// Inicializar widget com tipagem
const widget: WidgetInstance = window.PumaHelp.init({
appName: 'minha-empresa',
apiKey: 'rk_live_xxxxx',
theme: 'dark',
language: 'pt-BR',
});
// Identificar usuário autenticado
window.PumaHelp.identify({
accessToken: user.token,
name: user.name,
});
// Escutar eventos com tipos
widget.on('ticket-created', (event: CustomEvent<{ ticketId: string }>) => {
console.log('Ticket criado:', event.detail.ticketId);
});
// Controlar widget
widget.open();
widget.close();
widget.toggle();
Uso em React
import { useEffect, useRef } from 'react';
// Tipo para a referência do widget
type WidgetRef = WidgetInstance | null;
function App() {
const widgetRef = useRef<WidgetRef>(null);
useEffect(() => {
// Inicializar widget
widgetRef.current = window.PumaHelp.init({
appName: 'minha-empresa',
apiKey: 'rk_live_xxxxx',
});
// Cleanup
return () => {
widgetRef.current?.destroy();
};
}, []);
// Identificar usuário quando logar
const handleLogin = (user: { token: string; name: string }) => {
window.PumaHelp.identify({
accessToken: user.token,
name: user.name,
});
};
return <button onClick={() => widgetRef.current?.open()}>Abrir Suporte</button>;
}
🎨 Customização de CSS com ::part()
O widget utiliza Shadow DOM para isolamento completo de estilos, mas expõe CSS Parts específicos que permitem customização visual controlada usando o pseudo-elemento ::part().
Parts Disponíveis
| Part Name | Elemento | Descrição |
|---|---|---|
puma-widget-wrapper | Container Principal | Wrapper externo do widget inteiro |
puma-widget-content | Container do Conteúdo | Container da janela do chat (quando aberto) |
puma-widget-trigger | Botão de Acionamento | Botão flutuante que abre/fecha o widget |
puma-widget-tickets-list | Lista de Tickets | Container da lista de conversas |
puma-widget-first-ticket-form | Formulário Inicial | Formulário de criação de novo ticket |
puma-widget-ticket-chat | Chat de Ticket | Visualização de conversa ativa |
puma-widget-message-item | Item de Mensagem | Container de cada mensagem individual (agente ou usuário) |
puma-widget-message-item-agent | Mensagem do Agente | Mensagem enviada por um agente de suporte |
puma-widget-message-item-user | Mensagem do Usuário | Mensagem enviada pelo usuário final |
Como Usar
Use o seletor ::part() no seu CSS para customizar os elementos expostos do widget:
/* Customizar o botão do widget */
puma-help-widget::part(puma-widget-trigger) {
/* Seus estilos customizados */
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
/* Customizar a janela do chat */
puma-help-widget::part(puma-widget-content) {
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
/* Customizar o wrapper principal */
puma-help-widget::part(puma-widget-wrapper) {
/* Posicionamento, z-index, etc */
z-index: 99999;
}
Exemplos Práticos
Exemplo 1: Botão com Estilo Personalizado
puma-help-widget::part(puma-widget-trigger) {
/* Adicionar uma borda */
border: 3px solid #fff;
/* Sombra customizada */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
/* Aumentar tamanho */
transform: scale(1.1);
}
/* Hover state */
puma-help-widget::part(puma-widget-trigger):hover {
transform: scale(1.2);
}
Exemplo 2: Janela de Chat Customizada
puma-help-widget::part(puma-widget-content) {
/* Bordas arredondadas diferentes */
border-radius: 20px 20px 0 0;
/* Sombra mais pronunciada */
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
/* Altura customizada */
max-height: 600px;
}
Exemplo 3: Lista de Tickets com Fundo Customizado
puma-help-widget::part(puma-widget-tickets-list) {
/* Padrão de fundo */
background-image: linear-gradient(
45deg,
rgba(255, 255, 255, 0.05) 25%,
transparent 25%
);
}
Exemplo 4: Customizar Mensagens Individuais
/* Estilizar todas as mensagens */
puma-help-widget::part(puma-widget-message-item) {
/* Adicionar animação de entrada */
animation: slideIn 0.3s ease-out;
}
/* Estilizar apenas mensagens do agente */
puma-help-widget::part(puma-widget-message-item-agent) {
/* Espaçamento customizado */
margin-bottom: 12px;
/* Efeito de destaque */
position: relative;
}
/* Estilizar apenas mensagens do usuário */
puma-help-widget::part(puma-widget-message-item-user) {
/* Espaçamento customizado */
margin-bottom: 12px;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Customização de Tema via CSS Variables
Você pode customizar todas as cores e variáveis do widget usando ::part() no wrapper principal.
Formato HSL (Compatível com Tailwind)
O widget usa internamente o formato HSL sem vírgulas (H S% L%) para compatibilidade com classes de opacidade do Tailwind:
puma-help-widget::part(puma-widget-wrapper) {
--primary: 220 90% 56%; /* Azul */
--background: 0 0% 100%; /* Branco */
--foreground: 222 47% 11%; /* Texto escuro */
--muted: 210 40% 96%; /* Cinza claro */
--border: 214 32% 91%; /* Bordas */
}
Formato HEX (Mais Simples)
Você também pode usar cores em formato HEX diretamente:
puma-help-widget::part(puma-widget-wrapper) {
--primary: #3b82f6; /* Azul */
--primary-foreground: #ffffff; /* Branco */
--background: #ffffff; /* Fundo branco */
--foreground: #1f2937; /* Texto escuro */
--muted: #f3f4f6; /* Cinza claro */
--muted-foreground: #6b7280; /* Texto secundário */
--secondary: #e5e7eb; /* Bubbles do agente */
--secondary-foreground: #1f2937; /* Texto nas bubbles */
--border: #e5e7eb; /* Bordas */
--input: #e5e7eb; /* Fundo de inputs */
--ring: #3b82f6; /* Cor do foco */
--destructive: #ef4444; /* Erros */
}
CSS Variables Disponíveis
| Variável | Descrição | Exemplo HEX |
|---|---|---|
--primary | Cor principal (botões, destaques) | #3b82f6 |
--primary-foreground | Texto sobre cor primária | #ffffff |
--background | Fundo do widget | #ffffff |
--foreground | Cor do texto principal | #1f2937 |
--muted | Fundo de elementos secundários | #f3f4f6 |
--muted-foreground | Texto secundário | #6b7280 |
--secondary | Bubbles do agente | #e5e7eb |
--secondary-foreground | Texto nas bubbles do agente | #1f2937 |
--border | Cor das bordas | #e5e7eb |
--input | Fundo de inputs | #e5e7eb |
--ring | Cor do foco | #3b82f6 |
--destructive | Erros e alertas | #ef4444 |
--radius | Raio de bordas | 0.5rem |
Exemplos de Temas
Tema Azul Corporativo (HEX):
puma-help-widget::part(puma-widget-wrapper) {
--primary: #2563eb;
--primary-foreground: #ffffff;
--background: #ffffff;
--foreground: #1e293b;
--muted: #f1f5f9;
--muted-foreground: #64748b;
--border: #e2e8f0;
}
Tema Roxo Escuro (HEX):
puma-help-widget::part(puma-widget-wrapper) {
--primary: #8b5cf6;
--primary-foreground: #ffffff;
--background: #1e1b2e;
--foreground: #f5f3ff;
--muted: #2e2942;
--muted-foreground: #a5a0c2;
--secondary: #362f50;
--secondary-foreground: #f5f3ff;
--border: #362f50;
}
Tema Verde Natureza (HEX):
puma-help-widget::part(puma-widget-wrapper) {
--primary: #22c55e;
--primary-foreground: #ffffff;
--background: #0f1a14;
--foreground: #ecfdf5;
--muted: #1a2e23;
--muted-foreground: #86efac;
--border: #1a2e23;
}
Estilos Diferentes para Light e Dark Mode
Use seletores de atributo para aplicar estilos diferentes baseado no tema:
/* Estilos para Light Mode */
puma-help-widget[theme="light"]::part(puma-widget-wrapper) {
--primary: #2563eb;
--background: #ffffff;
--foreground: #1f2937;
--muted: #f3f4f6;
--border: #e5e7eb;
}
puma-help-widget[theme="light"]::part(puma-widget-content) {
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
}
/* Estilos para Dark Mode */
puma-help-widget[theme="dark"]::part(puma-widget-wrapper) {
--primary: #3b82f6;
--background: #111827;
--foreground: #f9fafb;
--muted: #1f2937;
--border: #374151;
}
puma-help-widget[theme="dark"]::part(puma-widget-content) {
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.1);
}
puma-help-widget[theme="dark"]::part(puma-widget-trigger) {
border: 2px solid rgba(255, 255, 255, 0.2);
}
Limitações
Os ::part() permitem estilizar os elementos expostos e customizar CSS Variables. Porém, não é possível acessar elementos internos não expostos.
O que você PODE fazer:
- ✅ Modificar layout, posicionamento, dimensões
- ✅ Adicionar bordas, sombras, fundos
- ✅ Aplicar transformações
- ✅ Ajustar opacidade, visibilidade
- ✅ Customizar todas as cores do tema via CSS Variables
O que você NÃO PODE fazer:
- ❌ Estilizar elementos filhos dentro dos parts
- ❌ Acessar elementos internos não expostos
- ❌ Sobrescrever completamente a estrutura do widget
Compatibilidade
O ::part() é suportado em todos os navegadores modernos:
- ✅ Chrome/Edge 73+
- ✅ Firefox 72+
- ✅ Safari 13.1+
- ✅ Opera 60+
Para navegadores mais antigos, os estilos customizados são simplesmente ignorados (graceful degradation).
Combinando com Props de Configuração
Você pode combinar ::part() com as propriedades de configuração para máxima flexibilidade:
<!-- HTML -->
<puma-help-widget
app-name="acme"
api-key="key-abc123"
theme="dark"
color="#2563eb"
></puma-help-widget>
/* CSS */
puma-help-widget::part(puma-widget-trigger) {
/* Customizações adicionais além da cor primária */
border: 2px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
📋 Métodos da API
Todos os métodos disponíveis na instância do widget:
Métodos de Controle
const widget = window.PumaHelp.init({ /* config */ });
// Abrir/fechar widget
widget.open(); // Abre a interface do chat
widget.close(); // Fecha a interface do chat
widget.toggle(); // Alterna entre aberto/fechado
// Mostrar/ocultar botão do widget
widget.hide(); // Oculta o botão do widget
widget.show(); // Mostra o botão do widget
// Verificar estado
console.log(widget.isOpen); // boolean
console.log(widget.isHidden); // boolean
Métodos de Autenticação
// Identificar usuário autenticado
widget.identify({
accessToken: 'seu-jwt-token', // Obrigatório
name: 'João Silva' // Opcional (recomendado)
});
// Logout (retorna ao modo visitante)
widget.logout();
Métodos de Ciclo de Vida
// Destruir instância única
widget.destroy();
// Destruir todos os widgets na página
window.PumaHelp.destroyAll();
Listener de Eventos
// Ouvir eventos
const unsubscribe = widget.on('ticket-created', (event) => {
console.log('ID do Ticket:', event.detail.ticketId);
});
// Parar de ouvir
unsubscribe();
🎧 Referência de Eventos
Inscreva-se em eventos do widget para rastrear interações do usuário:
Eventos de Ciclo de Vida
| Evento | Payload | Descrição |
|---|---|---|
ready | - | Widget inicializado e pronto |
error | { error, message } | Ocorreu um erro |
destroy | - | Widget destruído |
Eventos de Estado
| Evento | Payload | Descrição |
|---|---|---|
open | - | Widget aberto |
close | - | Widget fechado |
hide | - | Botão do widget oculto |
show | - | Botão do widget mostrado |
toggle | - | Widget aberto/fechado |
Eventos de Ação do Usuário
| Evento | Payload | Descrição |
|---|---|---|
ticket-created | { payload } | Novo ticket criado (objeto completo do ticket) |
ticket-updated | { payload: { ticketPublicId, comment: { body } } } | Ticket atualizado (mensagem enviada) |
Exemplos de payload:
widget.on('ticket-created', (event) => {
const { payload } = event.detail;
// Objeto completo do ticket da API
console.log(payload.public_id);
console.log(payload.subject);
console.log(payload.status);
console.log(payload.created_at);
});
widget.on('ticket-updated', (event) => {
const { payload } = event.detail;
console.log(payload.ticketPublicId);
console.log(payload.comment.body);
});
Eventos de Autenticação
| Evento | Payload | Descrição |
|---|---|---|
auth-error | { code, message, canRetry } | Erro de autenticação (ex: token expirado) |
Eventos de Interceptação de Payload (Avançado)
| Evento | Payload | Descrição |
|---|---|---|
before-ticket-create | { payload } | Interceptar/modificar dados do ticket antes da criação |
before-ticket-update | { payload } | Interceptar/modificar dados antes de atualizar ticket |
Exemplos de Eventos
const widget = window.PumaHelp.init({ /* config */ });
// Rastrear quando usuários criam tickets
widget.on('ticket-created', (event) => {
const { ticketId, subject } = event.detail;
analytics.track('Ticket de Suporte Criado', { ticketId, subject });
});
// Lidar com expiração de token
widget.on('auth-error', async (event) => {
if (event.detail.canRetry) {
const newToken = await refreshUserToken();
widget.identify({ accessToken: newToken });
}
});
// Rastrear uso do widget
widget.on('open', () => {
analytics.track('Widget Aberto');
});
🎨 Interceptores de Payload (Avançado)
Modifique dados do ticket/mensagem antes de enviar ao servidor:
Antes de Criar Ticket
widget.on('before-ticket-create', (event) => {
// Adicionar tags personalizadas
event.detail.payload.tags = ['vip', user.plan];
// Modificar assunto
const prefix = user.isPremium ? '[VIP]' : '';
event.detail.payload.subject = `${prefix} ${event.detail.payload.subject}`;
});
Estrutura do payload:
{
subject: string;
comment: { body: string };
via: { channel: 'widget' };
tags?: string[];
}
Antes de Atualizar Ticket (Enviar Mensagem)
widget.on('before-ticket-update', (event) => {
// Adicionar informações de rastreamento
const original = event.detail.payload.comment.body;
event.detail.payload.comment.body = `${original}\n\n<!-- session: ${sessionId} -->`;
});
Estrutura do payload:
{
comment: { body: string };
}
Casos de uso:
- Adicionar tags dinâmicas baseadas no contexto do usuário
- Incluir metadados para analytics
- Rastrear contexto da conversa
🔐 Autenticação de Usuário
Padrão Recomendado
Separe configuração da autenticação:
// 1. Inicializar widget no carregamento da página (config estática)
window.PumaHelp.init({
appName: 'acme',
apiKey: 'key-abc123'
});
// 2. Identificar usuário quando fizer login (auth dinâmica)
function onUserLogin(user) {
window.PumaHelp.identify({
accessToken: user.jwtToken,
name: user.fullName // Recomendado para fallback de visitante
});
}
// 3. Logout quando o usuário sair
function onUserLogout() {
window.PumaHelp.logout(); // Widget continua no modo visitante
}
Tratamento de Expiração de Token
Trate erros de autenticação quando o token expirar:
const widget = window.PumaHelp.init({ /* config */ });
widget.on('auth-error', async (event) => {
const { code, message, canRetry } = event.detail;
if (canRetry) {
try {
// Renovar token via seu backend
const newToken = await fetch('/api/auth/refresh').then(r => r.json());
// Atualizar widget com novo token
widget.identify({
accessToken: newToken.accessToken,
name: currentUser.name
});
} catch (error) {
// Não conseguiu renovar - redirecionar para login
window.location.href = '/login?expired=true';
}
}
});
🌐 Integração com Frameworks
React
import { useEffect, useRef } from 'react';
function App() {
const widgetRef = useRef(null);
useEffect(() => {
const widget = widgetRef.current;
if (!widget) return;
// Ouvir eventos
const unsubscribe = widget.addEventListener('ready', () => {
console.log('Widget pronto!');
});
return () => widget.removeEventListener('ready', unsubscribe);
}, []);
return (
<puma-help-widget
ref={widgetRef}
app-name="acme"
api-key="key-abc123"
theme="dark"
/>
);
}
Vue 3
<template>
<puma-help-widget
ref="widget"
app-name="acme"
api-key="key-abc123"
@ready="onReady"
@ticket-created="onTicketCreated"
/>
</template>
<script setup>
import { ref } from 'vue';
const widget = ref(null);
const onReady = () => {
console.log('Widget pronto!');
};
const onTicketCreated = (event) => {
console.log('Ticket:', event.detail.ticketId);
};
</script>
Angular
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<puma-help-widget
#widget
app-name="acme"
api-key="key-abc123"
></puma-help-widget>
`
})
export class AppComponent implements AfterViewInit {
@ViewChild('widget') widget!: ElementRef;
ngAfterViewInit() {
const el = this.widget.nativeElement;
el.addEventListener('ready', () => {
console.log('Widget pronto!');
});
}
}
🎯 Casos de Uso Comuns
Abrir widget programaticamente
// De um botão
document.getElementById('help-btn').addEventListener('click', () => {
const widget = document.querySelector('puma-help-widget');
widget.open();
});
// Ou com a API JavaScript
const widget = window.PumaHelp.init({ /* config */ });
widget.open();
Rastrear analytics
const widget = window.PumaHelp.init({ /* config */ });
widget.on('ticket-created', (e) => {
gtag('event', 'ticket_suporte_criado', {
ticket_id: e.detail.ticketId
});
});
widget.on('open', () => {
gtag('event', 'widget_aberto');
});
Aplicações multi-página (SPAs)
// Na mudança de rota, destruir e recriar se necessário
function onRouteChange(route) {
if (route === '/contato') {
// Criar widget para a página de contato
window.PumaHelp.init({ /* config */ });
} else {
// Remover de outras páginas
window.PumaHelp.destroyAll();
}
}
🐛 Debug
Habilite o modo debug para ver logs do widget:
window.PumaHelp.init({
appName: 'acme',
apiKey: 'key-abc123',
debug: true // Loga todos os eventos e mudanças de estado
});
Ou use o atributo HTML:
<puma-help-widget
app-name="acme"
api-key="key-abc123"
debug
></puma-help-widget>
🔊 Notificações Sonoras
O widget reproduz notificações de áudio para interações do usuário:
Tipos de Som:
- Som de Envio: Reproduzido quando você envia uma mensagem ou cria um ticket
- Som de Recebimento: Reproduzido quando um agente responde ao seu ticket
Configuração:
// Habilitar sons (padrão)
window.PumaHelp.init({
appName: 'acme',
apiKey: 'key-abc123',
soundEnabled: true
});
// Desabilitar sons
window.PumaHelp.init({
appName: 'acme',
apiKey: 'key-abc123',
soundEnabled: false
});
Atributo HTML:
<!-- Habilitar sons -->
<puma-help-widget
app-name="acme"
api-key="key-abc123"
sound-enabled
></puma-help-widget>
<!-- Desabilitar sons -->
<puma-help-widget
app-name="acme"
api-key="key-abc123"
sound-enabled="false"
></puma-help-widget>
Notas:
- Sons respeitam as políticas de autoplay do navegador
- Volume é otimizado automaticamente (envio: 50%, recebimento: 30%)
- Sons são carregados do CDN e funcionam tanto em desenvolvimento quanto em produção
📎 Anexos de Arquivos
O widget suporta anexos de arquivos tanto no formulário "Nova Conversa" quanto na visualização do chat ativo.
Recursos:
- Botão de Upload: Usuários podem clicar no ícone de clipe de papel para selecionar arquivos de seu dispositivo.
- Copiar/Colar: Usuários podem colar imagens diretamente da área de transferência (Ctrl+V) na área de entrada de mensagem.
- Múltiplos Arquivos: Múltiplos arquivos podem ser anexados e enviados em uma única mensagem.
- Pré-visualização: Arquivos anexados são mostrados em uma lista de pré-visualização onde podem ser removidos antes do envio.
❓ Perguntas Frequentes
P: Posso ter múltiplos widgets em uma página?
R: Sim! Cada chamada de init() ou elemento <puma-help-widget> cria uma instância separada.
P: Como personalizo a aparência do widget?
R: Você tem duas opções:
- Configuração básica: Use as props
theme,coloreiconpara customizações rápidas. - Customização avançada: Use CSS Parts com
::part()para estilizar elementos específicos (veja seção "Customização de CSS com::part()").
P: Posso modificar o CSS do widget?
R: Sim! O widget expõe CSS Parts que podem ser estilizados usando ::part(). Você pode customizar elementos como o botão (puma-widget-trigger), janela do chat (puma-widget-content), lista de tickets, e mais. Veja a documentação completa na seção "Customização de CSS com ::part()".
P: O que acontece quando um usuário faz logout?
R: Chame widget.logout() para limpar a autenticação. O widget continua funcionando no modo visitante.
P: Como lidar com expiração de token?
R: Ouça o evento auth-error e renove o token via widget.identify().
P: Posso modificar dados do ticket antes de enviar?
R: Sim! Use os eventos before-ticket-create ou before-ticket-update.
Versão: 2.1.0
Última Atualização: Dezembro 2025