Em resumo
Crie uma conta gratuita na Nexoply e copie a chave do seu chatbot na página Chatbot do painel. No App Router, adicione <Script src="https://nexoply.com/widget.js" data-chatbot={key} strategy="afterInteractive" /> do next/script dentro de <body> em app/layout.tsx; no Pages Router, coloque o mesmo <Script> em pages/_app.tsx. Não há pacote npm para instalar: o widget roda só no navegador, mantém a conversa durante a navegação no lado do cliente e não mexe no seu markup, então não há problemas de hidratação.
- Sem pacote npm: uma tag next/script no seu layout raiz (App Router) ou no _app (Pages Router).
- Guarde a chave em NEXT_PUBLIC_NEXOPLY_KEY; ela é pública, não é um segredo e não dá acesso à sua conta.
- Use strategy="afterInteractive" (a escolha padrão) ou "lazyOnload" para carregá-lo depois de todo o resto.
- Compatível com SSR: roda só no navegador, é montado em um Shadow DOM no document.body e sobrevive às mudanças de rota.
- Abra o chat pelo seu próprio botão com window.dispatchEvent(new Event("nexoply:open-chat")).
Antes de começar
- Uma conta na Nexoply. Cadastre-se grátis: o plano Free inclui 100 conversas por mês, sem cartão.
- As informações do negócio na Nexoply: serviços e preços, perguntas frequentes, políticas, horários e áreas de atendimento. O jeito mais rápido é digitar o endereço do site e deixar a Nexoply importar as páginas públicas (inclusive as geradas com JavaScript); você revisa as sugestões e nada é adicionado até você aprovar.
- A chave do seu chatbot. No painel, abra Chatbot (clique em Criar chatbot se ainda não criou). O código de instalação que aparece ali traz a chave no atributo data-chatbot.
Em um site HTML simples, o código de instalação seria colado antes de </body>:
<script src="https://nexoply.com/widget.js" data-chatbot="YOUR-KEY" async></script>No Next.js você não edita o HTML diretamente, então adiciona o mesmo script com o componente nativo next/script. A chave é pública: ela só diz ao widget a qual negócio ele pertence.
App Router: adicione o script em app/layout.tsx
O layout raiz envolve todas as páginas, então adicionar o script ali coloca o chat no site inteiro. Importe Script de next/script e coloque-o dentro de <body>, depois de {children}:
// app/layout.tsx
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
{/* Widget de chat da Nexoply: carrega no navegador depois da hidratação */}
<Script
src="https://nexoply.com/widget.js"
data-chatbot={process.env.NEXT_PUBLIC_NEXOPLY_KEY}
strategy="afterInteractive"
/>
</body>
</html>
);
}Depois coloque a chave em uma variável de ambiente. O prefixo NEXT_PUBLIC_ faz o Next.js incluí-la no bundle do navegador, o que não tem problema aqui porque a chave não é um segredo:
# .env.local (não vai para o git)
NEXT_PUBLIC_NEXOPLY_KEY=YOUR-KEYPages Router: adicione o script em pages/_app.tsx
No Pages Router, pages/_app.tsx envolve todas as páginas, então o mesmo <Script> vai ali, ao lado de <Component {...pageProps} />. Use a mesma variável do .env.local:
// pages/_app.tsx
import type { AppProps } from "next/app";
import Script from "next/script";
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<Script
src="https://nexoply.com/widget.js"
data-chatbot={process.env.NEXT_PUBLIC_NEXOPLY_KEY}
strategy="afterInteractive"
/>
</>
);
}Se o seu projeto combina os dois routers, adicione o script tanto em app/layout.tsx quanto em pages/_app.tsx. Carregá-lo duas vezes não causa problema: o widget é montado uma única vez por chave de chatbot.
Escolher uma estratégia e como ele se comporta
strategy="afterInteractive" carrega o widget logo que a página fica interativa, então o botão de chat aparece rápido. strategy="lazyOnload" espera o navegador ficar ocioso e todo o resto carregar; escolha essa opção se quiser o primeiro carregamento o mais leve possível e não se importar que o botão apareça um instante depois. Nenhuma das duas coloca o script no caminho crítico de renderização. Veja a documentação do next/script para mais detalhes.
- Navegação no lado do cliente. O widget mantém a conversa aberta enquanto os visitantes passam de uma página para outra com <Link> ou o router, e confere de novo as suas regras de página quando a URL muda, sem código extra.
- Seguro com SSR e hidratação. Roda só no navegador e é montado no document.body, fora do markup que o React hidrata, então nunca causa erros de hidratação.
- Shadow DOM. O seu CSS global ou do Tailwind não afeta o chat, e os estilos dele não afetam o seu app. Novas renderizações nunca o removem.
- StrictMode e Fast Refresh. Mesmo com efeitos rodando duas vezes em desenvolvimento ou hot reload, não surge um segundo chat: ele é montado uma vez por chave.
- Armazenamento. Não usa cookies; usa localStorage para um identificador anônimo do visitante e sessionStorage para a conversa atual.
Abra o chat pelo seu próprio botão
Quer um botão "Fale com a gente" na seção principal ou de preços? Dispare o evento nexoply:open-chat no window. Como ele usa onClick, precisa ser um componente de cliente:
"use client";
// components/ChatButton.tsx
export function ChatButton() {
return (
<button
type="button"
// abre a janela de chat da Nexoply
onClick={() => window.dispatchEvent(new Event("nexoply:open-chat"))}
>
Chat with us
</button>
);
}Use <ChatButton /> em qualquer página ou componente de servidor. Não há uma API para remover o widget depois de carregado: para esconder o botão de mensagem em algumas páginas (por exemplo /checkout), adicione uma regra de página com "Sem botão" em Chatbot → Personalizar → Botão de mensagem → Diferente em algumas páginas.
Teste local, sites permitidos e CSP
Rode next dev, abra http://localhost:3000 e um botão de chat aparece no canto. Faça uma pergunta real, como "Vocês atendem aos fins de semana?"; em segundos a conversa aparece em Conversas no seu painel. As mudanças que você faz no painel chegam ao site em cerca de um minuto, sem novo deploy.
Se o seu app envia um cabeçalho Content-Security-Policy (por exemplo pelo middleware ou pelo next.config), libere a Nexoply em:
- script-src https://nexoply.com: para carregar o widget.js.
- connect-src https://nexoply.com: para as requisições do chat.
- img-src https://nexoply.com: para imagens como o logo e o ícone do botão.
Solução de problemas e próximos passos
- Sem botão, e data-chatbot vazio no código da página. A variável de ambiente não foi lida: confira o prefixo NEXT_PUBLIC_, reinicie o next dev e, na hospedagem, adicione a variável e faça um novo deploy.
- O script está em uma página só, e não no layout. Coloque-o em app/layout.tsx ou pages/_app.tsx para carregar em todas as rotas.
- A tag foi alterada. Ela precisa manter o atributo data-chatbot e um src que contenha widget.js.
- Bloqueado pela CSP ou pelos sites permitidos. Procure erros no console do navegador e confira as duas seções acima.
- Chatbot desligado. Verifique se a chave Chatbot ativado está ligada.
- Bloqueadores de anúncios. Raramente, uma extensão bloqueia widgets de chat. Teste em uma janela anônima sem extensões.
Quando estiver funcionando, deixe-o com a cara do site em Chatbot → Personalizar: ícone, texto, cores e posição do botão, ou uma aba lateral na borda da tela (como "Ajuda"); um visual diferente no celular; e regras de página para páginas escolhidas (por exemplo, uma aba lateral só em /pricing). Veja os recursos e como funciona, compare os preços ou leia os guias de React e Vue.
Perguntas frequentes
Existe um pacote npm da Nexoply para Next.js?
Não, e você não precisa de um. O widget é sempre o script https://nexoply.com/widget.js com um atributo data-chatbot, adicionado com next/script. Todas as configurações ficam no seu painel da Nexoply.
Funciona na Vercel?
Sim. É só uma tag script carregada no navegador do visitante: nada roda no seu servidor, e não há rotas de API nem configurações de servidor para adicionar. Defina NEXT_PUBLIC_NEXOPLY_KEY nas variáveis de ambiente do seu projeto na Vercel e faça um novo deploy.
Afeta as Core Web Vitals ou o desempenho?
Ele foi feito para não afetar. O script carrega de forma assíncrona depois da hidratação (afterInteractive) ou quando o navegador fica ocioso (lazyOnload), então nunca bloqueia a renderização, e é montado fora do layout da sua página.
App Router ou Pages Router: qual devo usar?
O que o seu projeto já usa; o widget funciona igual nos dois. App Router: app/layout.tsx. Pages Router: pages/_app.tsx.
Posso carregá-lo só depois do consentimento de cookies?
Sim. Renderize o <Script> só depois que o visitante aceitar, por exemplo em um componente de cliente que verifique o seu estado de consentimento. O widget em si não usa cookies.
