19/08/2026

Nosso primeiro app na Shopify App Store: Simple WhatsApp Button

Publicamos nosso primeiro app na Shopify App Store. Escolhemos de propósito o escopo mais simples possível para atravessar o processo inteiro: um botão flutuante de WhatsApp, gratuito, sem servidor e sem um único script na loja. O que aprendemos, incluindo duas recusas na revisão por um bug que não existia.

Nosso primeiro app na Shopify App Store: Simple WhatsApp Button

Publicar um app na Shopify App Store é um daqueles processos que você só entende depois de atravessar inteiro. Tem checklist de requisitos, revisão automatizada, revisão humana, política de privacidade, webhooks obrigatórios e uma quantidade de detalhe que não aparece em nenhum tutorial.

Então a decisão foi essa: em vez de tentar um app ambicioso e travar no meio do caminho, escolher o escopo mais simples que ainda entregasse valor real, e usar esse app pra percorrer o processo do começo ao fim. Aprender a estrada com um carro simples.

O resultado está no ar: Simple WhatsApp Button, gratuito, publicado em 11 de agosto de 2026.

Por que um botão de WhatsApp

Simples não podia significar inútil. O app precisava resolver algo que praticamente toda loja brasileira precisa.

Botão de WhatsApp é exatamente isso. Qualquer loja que usa WhatsApp como canal de atendimento, que aqui é quase todas, precisa de um jeito de colocar aquele botão flutuante na loja. E as opções costumam ser ruins: ou você mexe no código do tema, ou instala um app pesado cheio de coisa que você não pediu.

A proposta é um botão flutuante configurável em mensagem, cor, tamanho e posição. Só isso, mas bem feito.

O foco foi não precisar de desenvolvedor

Essa foi a régua do produto inteiro: o lojista tem que instalar, configurar e ver funcionando sozinho, sem abrir código e sem chamar ninguém.

Na prática isso virou algumas decisões concretas:

  • Um número de telefone e o app já está no ar. Todo o resto tem default sensato. A configuração mínima é literalmente preencher um campo.
  • Uma única página de ajustes. Nada de menu com abas, seções escondidas ou configuração espalhada entre o app e o editor de temas.
  • Prévia em tempo real. O lojista vê exatamente como o botão vai ficar antes de salvar, com a cor, o tamanho e a animação que ele escolheu. Isso elimina o ciclo de salvar, abrir a loja em outra aba, olhar, voltar e ajustar.
  • Português e inglês desde o primeiro dia, detectando o idioma do admin da Shopify.

Tem um detalhe de configuração que resume bem a filosofia: o bloco no editor de temas mostra o liga/desliga, sem nenhuma outra opção. Foi de propósito. Se a mesma configuração existisse nos dois lugares, o lojista poderia configurar de um jeito no app e de outro no tema, e discordar de si mesmo. A configuração mora num lugar só.

O que é ajustável, para quem quer ajustar: cor do botão, cor do ícone, tamanho (de 32 a 96 px), proporção do ícone dentro do botão, posição em quatro cantos, animação (nenhuma, pulso ou salto), sombra e z-index.

Esse último parece detalhe de nerd mas resolve um problema real. Cabeçalhos fixos de tema costumam ficar em z-index 1000 e alguma coisa sempre passa por cima do botão. Em vez do app cravar um valor máximo e atropelar o tema de todo mundo, o default é modesto e o lojista aumenta se precisar.

Zero script na loja

Esse era inegociável. App de loja tem fama de destruir performance, e com razão: muitos injetam JavaScript, carregam bibliotecas e adicionam requisições em toda página.

O widget do Simple WhatsApp Button não tem uma única tag <script>. É um app embed via Theme App Extension: um bloco Liquid de 5,5 KB e um CSS de 5,4 KB. Nada de JavaScript, nada de ScriptTag, nada de edição no código do tema, e zero código residual quando o lojista desinstala.

O botão é um link com CSS. Não precisa de JavaScript pra ser um link.

Dois detalhes de implementação que vieram dessa escolha:

  • Todas as classes são prefixadas com swb-, pra não colidir com nada do tema da loja.
  • Todas as medidas estão em px, nunca em rem. Tema que mexe no tamanho de fonte da raiz (um html { font-size: 62.5% }, por exemplo) encolheria o botão em mais de um terço sem ninguém entender por quê.

Sem servidor, quase

A restrição técnica que mais moldou o projeto: o app não tem backend próprio. Sem SSR, sem banco de dados, sem sessão, sem OAuth manual, sem webhook de produto. Ele compila para arquivos estáticos e conversa com a Shopify direto do navegador, via Direct API access.

A persistência inteira é um metafield de app: um JSON com as configurações, guardado na própria instalação do app. O admin escreve nele e o bloco Liquid lê dele na hora de renderizar. Não tem cache, não tem segunda cópia pra divergir, e não precisa de nenhum escopo de acesso, porque um metafield na sua própria instalação é seu por definição. Quando o lojista desinstala, as configurações morrem junto.

Só que "sem servidor" acabou não sendo 100% verdade, e essa foi uma das descobertas do processo. Dois endpoints foram inevitáveis, ambos rodando como Cloudflare Pages Functions, fora do app:

1. Os webhooks obrigatórios de compliance. Todo app da App Store precisa responder aos webhooks de privacidade (dados do cliente, dados da loja), mesmo que não colete dado nenhum. Não existe isenção. O handler valida o HMAC e confirma o recebimento, e não tem trabalho de dado nenhum a fazer, porque o app não guarda dado de comprador.

2. O endpoint de session token, que é a parte mais interessante. Esse é o que eu tinha esquecido, e vale explicar porque é um problema que só aparece nesse desenho de app.

A revisão automatizada da Shopify tem uma checagem de "app embutido" que verifica se o app usa session tokens corretamente. E ela verifica observando o tráfego: espera ver uma requisição do frontend para a URL do próprio app levando um Authorization: Bearer <JWT>.

O problema é que esse app nunca faz essa requisição naturalmente. Como tudo vai do navegador direto para a Shopify via Direct API, nada nunca toca o domínio do app. A checagem não tem tráfego pra observar, então fica vermelha para sempre e bloqueia a submissão.

A solução foi um endpoint que existe unicamente pra satisfazer essa verificação: o app dispara um POST autenticado por carregamento, e o endpoint valida o token de verdade (assinatura HS256 fixa, aud contra o client ID, exp/nbf com margem de cinco segundos, e o dest conferido como host .myshopify.com). Toda rejeição devolve um 401 idêntico, pra um token forjado não descobrir qual checagem ele falhou.

E o mais importante: ele engole qualquer erro. A funcionalidade real do app não depende desse endpoint, então uma requisição bloqueada não pode custar nada ao lojista.

A aprovação: recusado duas vezes por um bug que não existia

Aqui está a parte que ninguém conta.

Depois do checklist técnico cumprido, o app vai para revisão humana. Um testador do time da Shopify instala, testa e aprova ou recusa.

O nosso foi recusado duas vezes pelo mesmo motivo: segundo o testador, o botão não abria o WhatsApp.

Só que abria. Testamos em vários dispositivos, navegadores e lojas. O link estava correto, o número estava correto, o comportamento estava correto.

O que estava acontecendo era na ponta dele: alguma coisa na rede local ou na VPN que ele usava estava bloqueando links do WhatsApp. O app funcionava perfeitamente; o ambiente de teste é que barrava o destino.

Ao responder explicando isso, com detalhe do que tínhamos verificado, o app foi aprovado logo em seguida.

É a versão 1, e o plano é crescer de graça primeiro

O app está no ar como primeira versão, e é assim que ele foi pensado. O roadmap já tem várias funcionalidades, e a estratégia é deliberada:

Primeiro, mais recursos gratuitos. Ampliar o que o app faz sem cobrar, para construir base de instalação e avaliações. Um app com zero review não convence ninguém, e isso não se resolve com preço.

Depois, algo que justifique cobrança. Não uma versão capada do que já é grátis, mas uma funcionalidade realmente interessante, que resolva um problema maior.

E aí entra a segunda camada de aprendizado, que é a razão de tudo isso: cobrar significa mexer com a API de cobrança da Shopify, planos, assinaturas e todo o ciclo de faturamento. Ou seja, o mesmo movimento de novo, atravessar um processo desconhecido, mas dessa vez em cima de um app que já existe e já tem usuários.

Já sabemos até o caminho: quando for monetizar, o plano é usar o Shopify App Pricing, em que a Shopify hospeda a página de escolha de plano e processa a cobrança, e o app só consulta qual plano está ativo. A alternativa, a Billing API, exigiria escopo extra e um webhook de atualização de assinatura, e webhook precisa de servidor, o que desmontaria justamente o desenho sem backend que descrevi acima.

A stack

Para quem quer os detalhes técnicos:

CamadaTecnologia
Admin do appReact 18 + React Router 7, SPA estática (ssr: false)
UIPolaris web components + App Bridge
Widget da lojaTheme App Extension (Liquid + CSS, zero JS)
PersistênciaUm metafield de app (JSON), sem banco
EndpointsCloudflare Pages Functions (compliance + session token)
HospedagemCloudflare Pages
Escopos de acessoNenhum (scopes = "")

O app precisa de zero escopos de acesso. Não lê produto, não lê pedido, não lê cliente. A superfície de risco para o lojista é basicamente nula, e isso não foi um acidente: é consequência direta de manter o escopo pequeno.

Se você está construindo para Shopify, vale ler também o que escrevi sobre como manter o contexto do projeto no CLAUDE.md — esse app tem um dos arquivos de contexto mais densos que já escrevi, e boa parte das armadilhas acima está documentada lá justamente para não morder de novo.

Resumo

  • Simple WhatsApp Button: gratuito, na Shopify App Store desde 11 de agosto de 2026.
  • Escopo mínimo de propósito, para atravessar o processo inteiro de publicação.
  • Configuração em segundos, sem desenvolvedor: um número de telefone e está no ar.
  • Zero JavaScript no storefront, nenhum ScriptTag e nada residual após desinstalar.
  • Sem backend, exceto dois endpoints obrigatórios: compliance e session token.
  • Nenhum escopo de acesso: o app não lê produto, pedido nem cliente.
  • Versão 1, com roadmap de recursos gratuitos antes de qualquer cobrança.
  • Primeira semana no ar: 4 lojas instaladas, uma delas fora do Brasil, e uma avaliação 5 estrelas.

Se você tem loja Shopify e usa WhatsApp no atendimento, instala e me conta o que faltou. É exatamente esse feedback que vai definir o que entra na próxima versão.

#shopify #ecommerce #ferramenta #app

Tags

Se eu te ajudei de alguma forma e você quiser retribuir, pode me pagar um café ☕ ou ainda usar um dos meus links de indicação para abrir conta em serviços como Asaas, Bunny, Clara, assinar conteúdos gratuitos ou usar serviços recomendados.

Você pode me encontrar no: Github, Behance, LinkedIn, YouTube, Instagram, X ou por email hello@marciotoledo.com!

© 2002 - 2026 | Marcio Toledo. Todos os direitos reservados. For LLMs