Pular para o conteúdo

O widget

Uma tag de script, um botão flutuante, uma janela de feedback que funciona em qualquer página. Tudo abaixo são ajustes que você pode querer mudar, mas não precisa.

A tag de script

Cole isto no HTML de qualquer página onde quiser coletar feedback. Um botão flutuante aparece no canto; clique e uma janela de feedback abre.

html
<script
  src="https://opini.dev/widget.js"
  data-opini-key="pk_live_..."
  data-opini-label="Send feedback"
  data-opini-position="bottom-right"
  data-opini-theme="light"
  data-opini-accent="#C2410C"
  defer></script>

Roda o Opini em outra origem? Troque opini.dev pelo seu host. O widget descobre a partir daí para onde enviar.

Opções

Todos os ajustes ficam na tag de script como atributos data-*. Só a chave é obrigatória.

AtributoObrigatórioO que faz
data-opini-keysimA chave pública do widget do seu projeto (pk_live_...).
data-opini-labelnãoTexto do botão flutuante. O padrão é "Send feedback".
data-opini-positionnãoEm qual canto o botão fica. bottom-right (padrão), bottom-left, top-right, top-left.
data-opini-themenãolight (padrão) ou dark. Escolha o que combina com sua página.
data-opini-accentnãoA cor da sua marca no botão de enviar e nos contornos de foco. Qualquer cor CSS: hex, rgb() ou nome.
data-opini-basenãoAponta para outro host da API. Raramente necessário: o script descobre isso pelo próprio src.

Personalização no servidor

Os atributos data-* acima são o plano B. Ao carregar, o widget busca a configuração do projeto no Opini, e um admin pode trocar alguns textos sem mexer na tag de script da página:

  • widget_label: o texto do botão flutuante.
  • widget_headline: o título da janela.
  • widget_placeholder: o texto de exemplo do campo.
  • widget_submit_label: o botão de enviar.
  • widget_thanks: a mensagem de agradecimento depois de enviar.
  • accent_hex, widget_theme, widget_position: visual.

Prioridade: o servidor ganha, data-* preenche o que falta e os padrões cobrem o resto. Assim dá para mudar o visual de todos os widgets em todos os sites a partir de um lugar só, sem pedir para ninguém colar a tag de novo.

Se a busca da configuração falhar (offline, bloqueada, CORS), o widget carrega mesmo assim com os atributos e os padrões. A chamada de rede nunca bloqueia nada.

Identificar usuários

Diga ao Opini quem está enviando, para que o feedback chegue na triagem com um nome e o que mais você quiser passar.

O widget pede nome e e-mail a cada visitante para que seu time possa responder. Quando você passa name e email aqui, ele pula esses campos.

javascript
window.opini.identify({
  email: "[email protected]",
  name: "Ada Lovelace",
  plan: "pro",
  signed_up_at: "2024-11-02"
});

Algumas observações:

  • email: aparece só na triagem. Nunca em páginas públicas.
  • name: usado como nome de exibição na triagem e nas telas de admin.
  • Todo o resto (plano, data de cadastro, o que for) vai junto como contexto extra no painel de detalhes da triagem.

Chame sempre que souber quem é o usuário: ao carregar a página, depois do login, tanto faz. A última chamada antes do envio vale.

Para filtrar por um desses valores na lista de Feedback, use o filtro de Contexto com uma chave com ponto, como identify.plan.

Tags

O widget pode marcar o que as pessoas enviam, para chegar já organizado. Defina as tags iniciais com data-opini-tags e mude conforme as pessoas navegam no app com window.opini.setTags. Valem as últimas tags definidas antes do envio.

html
<script src="https://opini.dev/widget.js" data-opini-key="pk_live_…" data-opini-tags="web,beta" defer></script>
<script>
  window.opini.setTags(["web", "checkout"])
</script>

As tags precisam existir no projeto e estar permitidas na chave (Configurações do projeto → Chaves de API → Editar → Tags que esta chave pode definir). Se alguma não estiver, a mensagem é recusada e o console do navegador diz qual tag. Veja Tags no guia da API para os detalhes.

Tema

Dois ajustes. data-opini-theme escolhe claro (padrão, fundo branco) ou escuro (invertido). O widget vive dentro de um shadow root, então o CSS da sua página não vaza para dentro nem o quebra.

data-opini-accent é a cor da sua marca: ela pinta o botão de enviar e os contornos de foco. Qualquer cor CSS válida serve.

Perguntas de acompanhamento

A triagem não é uma caixa de mão única. Todo feedback tem um botão de pergunta de acompanhamento na tela de admin: faça uma pergunta e a pessoa recebe por e-mail um link para responder. Sem conta, sem login, só uma página com o trecho do feedback, a pergunta e um campo de texto.

A resposta volta para a mesma linha do feedback. Os links expiram em 30 dias e só podem ser respondidos uma vez. Página completa em Perguntas de acompanhamento.

Acessibilidade

Tudo o que você esperaria já está resolvido:

  • A janela se anuncia a leitores de tela como um diálogo com título.
  • Quem usa teclado navega pelo formulário sem o foco escapar para a página; Esc fecha a janela e devolve o foco ao botão que a abriu.
  • O botão flutuante é um botão de verdade, não uma div fingindo, e nenhum alvo de toque é menor que a ponta do dedo.
  • A cor de destaque vai para os contornos de foco, então quem usa teclado sempre sabe onde está.

Remover

Apague a tag de script. O widget não mexe em localStorage, sessionStorage nem cookies da sua página, então nada fica para trás.

Avançado

Provavelmente você não precisa de nada disto. Abra se precisar.

Usa uma Content Security Policy rígida?

Isto é o que liberar (supondo o Opini em opini.dev):

http
Content-Security-Policy:
  script-src 'self' https://opini.dev;
  connect-src 'self' https://opini.dev https://*.r2.cloudflarestorage.com;
  img-src 'self' blob:;
  style-src 'self' 'unsafe-inline';

O widget injeta seus estilos inline no próprio shadow root, então 'unsafe-inline' é necessário em style-src até termos carregamento de estilos com nonce. Sem eval, sem imagens externas, sem frames.

Anexos de imagem vão direto para o armazenamento (o host R2) e mostram uma prévia local (blob:). Se sua política exige Trusted Types, adicione opini-widget a trusted-types.

Tamanho exato do pacote

O widget é um único script: sem dependências, sem pedaços carregados depois, nada além da tag.

  • Com gzip: ~4.2 KB
  • Sem compressão: ~12 KB