Integrar uma app
Conecte sua aplicação ao Mira: origens, CSP, bridge, widget e verificação, com etapas opcionais para erros, source maps e contexto.
Esta trilha leva uma aplicação React 19 com Vite do zero até enviar reports pelo widget. Ela serve a duas pessoas: o admin do Mira, que configura o projeto no dashboard, e o dev da app, que mexe no código e no CI. Cada etapa diz quem faz.
O bridge (@mira/bridge) é o pacote que fica na app. Ele ativa a captura de console, erros e rede desde o carregamento, mostra o widget de report e expõe versão, usuário logado e estado da app. O widget funciona em desenvolvimento, QA e staging. Em produção, só a captura de erros roda, ativada pelo DSN.
O widget foi testado no Chrome e no Edge.
Visão geral
| Etapa | Quem faz | Obrigatória |
|---|---|---|
| 1. Cadastrar o ambiente e as origens | Admin | Sim |
| 2. Liberar a CSP | Dev | Sim |
| 3. Instalar o bridge | Dev | Sim |
| 4. Ativar o widget | Dev | Sim |
| 5. Verificar | Dev e admin | Sim |
| A. Capturar erros com o DSN | Admin e dev | Não |
| B. Enviar source maps no CI | Admin e dev | Não |
| C. Expor usuário e estado da app | Dev | Não |
Os três ambientes
Uma app costuma rodar em três lugares, e cada um ativa partes diferentes do bridge:
| Ambiente | Widget | Captura de erros (DSN) | Quem tem o ambiente no Mira |
|---|---|---|---|
| Desenvolvimento local | Sim | Opcional | Ambiente develop, com a origem http://localhost:5173 |
| Staging e QA | Sim | Sim | Ambiente staging ou qa, com a origem da app |
| Produção | Não | Sim | Ambiente production, só para erros |
O Mira só aceita chamadas e logins vindos das origens cadastradas no ambiente. Por isso, cada ambiente da tabela precisa existir no projeto.
Núcleo da integração
Passos obrigatórios
Cadastrar o ambiente e as origens
Quem faz: admin.
- Abra o menu do projeto, clique em Configurações do projeto e entre em Ambientes. O ambiente criado com o projeto já tem a origem da URL do app.
- Clique em Novo ambiente.
- Dê um nome, como
staging, e liste em Origens uma origem por linha. Cadastre a origem exata, com a porta quando houver, ou um padrão com*, comohttps://*.loja-demo.test. - Salve. Repita para cada ambiente da tabela acima.


Anote também o ID do projeto, que está em Configurações, Geral, com um botão de copiar. Você usa esse valor na etapa B.
Liberar a CSP
Quem faz: dev.
Se a app define uma Content-Security-Policy, ela precisa deixar a página falar com o Mira. Adicione a URL da instância em connect-src:
connect-src 'self' https://mira.example.com;
script-src 'self' https://mira.example.com;A interface do widget não vai no pacote: a página a importa da instância, em https://mira.example.com/widget/v1/widget.js, na primeira vez que o widget abre. Por isso a CSP também precisa de script-src para a instância. Se o módulo não carregar, o widget não abre e o console mostra [Mira] widget indisponível na instância.
O login do widget abre uma aba do dashboard, que não passa pela CSP da app. Se você ativar a captura de erros (etapa A), libere também o host do DSN em connect-src. Ele é o mesmo da instância.
Uma app sem cabeçalho de CSP já passa por esta etapa.
Instalar o bridge
Quem faz: dev.
O Mira serve os pacotes do SDK pela própria URL, sem login. Instale o bridge pela URL da instância:
npm install https://mira.example.com/downloads/sdk/mira-bridge-0.15.0.tgzO pacote pede React 19 e react-dom como peers, porque o ErrorBoundary e o widget usam o React da app. O lockfile fixa a integridade do arquivo. Uma versão publicada nunca muda, e as antigas continuam disponíveis. Para atualizar, troque a versão na URL.
Sem bundler, a instância também serve o widget como script. Cole no <head>, antes dos scripts da app, e pule o bootstrap.ts da próxima etapa:
<script src="https://mira.example.com/widget/v1/mira.js"></script>
<script>
mira.init({ widget: { instanceUrl: "https://mira.example.com", trigger: "button" } });
</script>O Guia de configuração do projeto mostra o mesmo trecho na aba Script, com a URL da instância preenchida. Pela tag de script, a CSP também bloqueia o mira.init inline: mova a chamada para um arquivo .js da app ou autorize-a com nonce.
Ativar o widget
Quem faz: dev.
Crie um bootstrap que inicializa o bridge antes da app e só então carrega o resto. Assim o bridge captura também os erros que acontecem durante o carregamento dos módulos.
// src/main.tsx
import "./bootstrap";Escolha o ambiente na aba. Cada uma traz o .env e o bootstrap.ts correspondentes.
# .env.development
VITE_MIRA_URL=https://mira.example.com// src/bootstrap.ts
import { mira } from "@mira/bridge";
import { widgetIntegration } from "@mira/bridge/widget";
mira.init({
integrations: [widgetIntegration({ instanceUrl: import.meta.env.VITE_MIRA_URL, trigger: "button" })],
});
await import("./app");Rode a app em http://localhost:5173 (ou na porta que você cadastrou) e use essa origem.
Em src/app.tsx, fica o conteúdo do antigo main.tsx: o createRoot e a renderização.
Imports estáticos rodam antes do corpo do arquivo. Por isso o await import("./app") vem depois do mira.init().
O parâmetro trigger escolhe como o widget abre:
trigger | Efeito |
|---|---|
"button" (padrão) | Botão flutuante com o símbolo do Mira e o atalho Alt+Shift+M |
"shortcut" | Só o atalho. Troque a combinação com shortcut: "Ctrl+Shift+M" |
"manual" | Nenhuma entrada visível. Chame mira.open() a partir de um item de menu da app |
O widget sempre abre num painel junto do botão. Sem botão ("shortcut" e "manual"), o painel fica no canto inferior direito. A opção mode das versões antigas é ignorada.
Para o widget copiar o link do report depois do envio, a página precisa permitir clipboard-write. Se a app roda o widget num iframe, declare allow="clipboard-write" nele. Sem a permissão, o painel mostra o link para copiar à mão.
Verificar
Quem faz: dev e admin.
- Abra a app no ambiente configurado. O botão do Mira aparece no canto da página.

- Clique no botão. Na primeira vez, o widget pede o login. Clique em Entrar: o painel mostra um código, e Aprovar no Mira abre o dashboard numa aba nova. Entre, confira que o código é o do painel e aprove o projeto e o ambiente que o Mira resolveu para a origem da app.

- Faça uma captura pelo menu do botão, ou escolha Novo report. O report abre num diálogo: o tipo começa em Bug (troque para Melhoria ou Sugestão se for o caso), preencha o título e a descrição (em Markdown) e clique em Criar.

- O painel troca o formulário por Report enviado.

- O admin abre o dashboard e confere que o report chegou à triagem do ambiente.

Se o botão não aparece ou o login falha, confira nesta ordem: a origem cadastrada bate com a da barra de endereço (incluindo a porta), a CSP libera a instância, o navegador não bloqueou a aba de aprovação e nenhum <dialog> modal está aberto por cima da página.
Etapas opcionais
A. Capturar erros com o DSN
Quem faz: admin gera a chave, dev configura a app. Vale para staging, QA e produção.
O DSN ativa o SDK de erros. Ele tem o formato https://<chave>@<host-do-mira>/<id-do-ambiente>, e a chave define o ambiente. Ela é pública e só escreve ocorrências daquele ambiente, então pode ir no bundle.
Gerar a chave
Quem faz: admin.
- Em Configurações do projeto, Erros, escolha o ambiente no seletor. A seção mostra o nível de dados e as chaves de ingestão.
- Dê um nome à chave, como
web, e clique em Gerar chave. - Copie o DSN pelo botão da linha.


Cada chave vale só para o ambiente em que foi gerada. Revogar não tem volta e faz as apps com aquele DSN pararem de enviar.
Configurar a app
Quem faz: dev.
Coloque o DSN em VITE_MIRA_DSN e use o bootstrap.ts da aba de staging ou de produção da etapa 4 (Ativar o widget). A release identifica a versão (1.4.0+abc1234), e o buildTime permite ao Mira reabrir sozinho um erro resolvido quando um build novo volta a falhar.
Libere o host do DSN em connect-src. A origem da app precisa estar cadastrada no ambiente, porque a ingestão confere a origem dos envios do navegador.
Conferir
Quem faz: dev e admin.
Provoque um erro na app e abra Erros no projeto. A ocorrência aparece agrupada em um erro novo.

O que o SDK captura, as opções de init, a captura manual e a redação estão em SDK.
B. Enviar source maps no CI
Quem faz: admin cria a credencial, dev configura o build.
Sem source maps, a stack de uma ocorrência chega minificada. O plugin Vite do @mira/sourcemaps gera os maps, injeta um Debug ID em cada script, envia os maps ao Mira e apaga os .map do dist. Os maps nunca vão para o servidor da app.
Criar a credencial de serviço
Quem faz: admin.
- Abra Admin, Serviços de API, e crie um serviço com os projetos da app.
- Ative só a permissão Permitir envio de source maps e desative as consultas.
- Em Chaves, informe nome e validade e use Emitir chave. O segredo (
mira_svc_...) aparece uma vez; salve no gerenciador de segredos do CI.
Veja os detalhes em Tokens.
Instalar o plugin
Quem faz: dev.
npm install --save-dev https://mira.example.com/downloads/sdk/mira-sourcemaps-0.1.1.tgz// vite.config.ts
import { miraSourceMaps } from "@mira/sourcemaps/vite";
import react from "@vitejs/plugin-react";
import { defineConfig, loadEnv } from "vite";
export default defineConfig(({ mode }) => {
// Lê os `.env` do modo (`.env.production`, `.env.staging`) junto com o ambiente do CI.
const env = loadEnv(mode, process.cwd(), "VITE_");
return {
plugins: [
react(),
miraSourceMaps({
release: `${env.VITE_VERSION}+${env.VITE_BUILD_SHA}`,
buildTime: env.VITE_BUILD_TIME,
}),
],
};
});Use a mesma release e o mesmo buildTime do mira.init, que lê os mesmos valores de import.meta.env.
Configurar o CI
Quem faz: dev.
O plugin lê três variáveis de ambiente:
| Variável | Valor |
|---|---|
MIRA_URL | https://mira.example.com. Precisa de https, porque o token vai num header; http só vale para localhost |
MIRA_PROJECT_ID | O ID do projeto, de Configurações, Geral |
MIRA_SOURCEMAPS_TOKEN | A credencial mira_svc_ da etapa anterior |
# .github/workflows/deploy.yml
- run: pnpm build
env:
MIRA_URL: https://mira.example.com
MIRA_PROJECT_ID: ${{ vars.MIRA_PROJECT_ID }}
MIRA_SOURCEMAPS_TOKEN: ${{ secrets.MIRA_SOURCEMAPS_TOKEN }}
- run: pnpm exec mira-sourcemaps check distO check falha se sobrar um .map no diretório ou se um .js ou .css tiver map inline (sourceMappingURL=data:). Rode antes de publicar.
Sem token, o build remove os maps sem enviar e avisa no log. Se o envio falhar, os .map saem do dist e o build falha. Publique a app só depois do envio: ocorrências que chegam antes dos maps ficam minificadas e formam outro erro.
Fora do Vite, o mesmo pacote traz o comando mira-sourcemaps upload <dir> --release <release> para um dist já gerado.
O que o Mira armazena do código depende do nível de código do projeto, em Configurações, Geral: sem código, só mapeamento (padrão) ou completo.
C. Expor usuário e estado da app
Quem faz: dev.
Versão e ambiente. O contexto vai junto de cada report:
mira.setContext({
version: import.meta.env.VITE_BUILD_SHA,
env: import.meta.env.MODE,
});setContext substitui o contexto inteiro. Para o usuário, chame as duas funções no login e no logout:
mira.setContext({ version, env, appUser: { id: user.id, email: user.email } });
mira.setUser({ id: user.id, email: user.email });
// no logout
mira.setUser(null);setContext vai para os reports e setUser para as ocorrências de erro. Depois do logout, o SDK volta ao id anônimo.
Estado. Registre um provider por fonte de estado. Ele só roda quando alguém envia um report e marca o contexto e estado da app entre as evidências.
import { dehydrate } from "@tanstack/react-query";
mira.register("tanstack-query", () => dehydrate(queryClient));
mira.register("router", () => router.state.location);Um provider que lança erro ou demora mais de 2 segundos é ignorado, e o report segue sem aquele snapshot.
Todos os membros do projeto veem o estado enviado. Não registre providers que devolvam tokens, credenciais ou dados pessoais reais. A redação automática cobre nomes de chave comuns, como token, password e secret, mas não reconhece dados pessoais.
Problemas comuns
| Sintoma | Causa provável |
|---|---|
| O botão não aparece | O bridge não foi inicializado nessa build, ou a app roda com a variável VITE_MIRA_URL vazia |
| O login do widget diz que não há ambiente para a origem | A origem da barra de endereço não está cadastrada no ambiente |
| A aprovação do login não termina | O código expira em 10 minutos. Clique em Entrar de novo e aprove o código novo, na mesma instância |
| O widget não recebe foco | Um <dialog> modal da app está aberto, ou uma biblioteca de focus trap bloqueia o foco. Feche o modal ou crie uma exceção para o host <mira-widget> |
| Os envios do SDK falham com erro de CSP | O host do Mira não está em connect-src |
| A stack das ocorrências chega minificada | Os source maps não foram enviados para essa release, ou a release do build difere da do init |