PS PrestaShop Intermédio

DataFirefly Push Pro: guia completo

Instalar, configurar e explorar o DataFirefly Push Pro para PrestaShop 8 e 9: Web Push VAPID nativo, opt-in inteligente, 9 automatizações, construtor de campanhas, segmentação, testes A/B, atribuição da receita, tópicos, inbox e webhooks assinados HMAC.

Atualizado Versão do módulo 1.2.0

O DataFirefly Push Pro traz as notificações push web nativas ao PrestaShop 8 e 9 sem nenhum serviço de terceiros do tipo OneSignal nem subscrição mensal. Este guia cobre a instalação, a configuração inicial, as nove automatizações, o construtor de campanhas, a segmentação, os testes A/B, a atribuição da receita, os tópicos, a inbox, os webhooks e a resolução de problemas.

1. Apresentação e casos de uso

O módulo implementa nativamente o protocolo Web Push VAPID (RFC 8292) com cifragem aes128gcm do lado do servidor. As subscrições são guardadas na sua base de dados PrestaShop, os envios partem diretamente do seu alojamento, nenhum dado passa por um serviço de terceiros.

Casos de uso típicos:

  • Recuperação de carrinhos abandonados: três lembretes espaçados (1 h, 24 h, 72 h) sem depender do e-mail do visitante.
  • Alertas de produto: reposição de stock, descida de preço, opt-in diretamente na página de produto.
  • Transacional: confirmação de encomenda, expedição, pedido de avaliação após a entrega.
  • Reativação: aniversário, clientes inativos, resumo dos novos produtos.
  • Campanhas pontuais: saldos, lançamentos, Black Friday, com segmentação e testes A/B.

2. Pré-requisitos

  • PrestaShop 8.0 a 9.x
  • PHP 7.4 no mínimo, 8.x recomendado
  • MySQL 5.7 no mínimo ou MariaDB 10.3
  • HTTPS obrigatório: a API Web Push dos navegadores só funciona numa origem segura. Só o localhost é exceção para os testes em desenvolvimento.
  • Um cron externo capaz de chamar um URL HTTP a cada 5 minutos (cron Linux, tarefas agendadas do alojamento, cron nativo do PrestaShop, etc.)
  • OpenSSL ativo no PHP (usado para a geração das chaves VAPID e a cifragem aes128gcm)

Porquê HTTPS? Todos os navegadores (Chrome, Firefox, Safari, Edge) recusam registar um service worker ou conceder a permissão de notificações numa página HTTP. É uma limitação dos navegadores, não do módulo.

Adaptação para Portugal: o módulo é entregue em FR, EN, ES, DE e IT. O português não está incluído: traduza as cadeias do módulo em Internacional → Traduções (pedido de opt-in, botões «Notify me», modal de gestão) e redija o título e o corpo de cada automatização em português no separador Automations, caso contrário os subscritores verão o texto em inglês.

3. Instalação

  1. Transfira o ZIP dfpushnotifications-v1.2.0-phase3.zip a partir da sua área de cliente DataFirefly.
  2. Back-office PrestaShop → Módulos → Gestor de módulos → Carregar um módulo → selecione o ZIP.
  3. Clique em Instalar. A instalação cria 14 tabelas com o prefixo ps_dfpush_*, gera um token de cron único e regista os separadores do BO.
  4. Aparece um novo menu: Melhorar → DataFirefly Push com 8 separadores (Dashboard, Campaigns, Automations, Queue, Subscribers, Topics, Webhooks, Settings).

4. Geração das chaves VAPID

As chaves VAPID identificam o seu servidor junto dos push services dos navegadores (FCM, Mozilla autopush, Apple push). São geradas uma única vez e nunca devem mudar depois da entrada em produção (caso contrário todos os subscritores ficam inalcançáveis).

  1. Aceda a DataFirefly Push → Opt-in & Settings.
  2. Clique em Generate VAPID keys. O módulo cria um par de chaves ECDSA P-256 guardado na configuração do PrestaShop.
  3. Introduza um VAPID subject: um URL mailto: com o seu endereço de contacto técnico (ex.: mailto:admin@asualoja.pt). É o identificador que os push services podem contactar em caso de abuso.
  4. Ative o módulo através do interruptor Push notifications enabled.

Guarde as suas chaves. Se regenerar as chaves VAPID depois do lançamento, todos os seus subscritores existentes serão rejeitados pelos push services com um código 410 Gone. Conserve uma cópia de segurança da base de dados PrestaShop antes de qualquer manipulação das chaves.

5. Configuração do opt-in

O separador Opt-in & Settings controla a apresentação do pedido de permissão. Estão disponíveis três estilos:

  • Bell: um sino flutuante no canto inferior direito. O utilizador clica, e o navegador mostra depois o seu pedido nativo. O menos intrusivo.
  • Banner: uma faixa persistente no topo ou no fundo da página com dois botões (autorizar / recusar).
  • Modal: uma janela modal centrada, mais visível mas também mais agressiva.

Gatilhos

Para não mostrar o pedido logo no primeiro segundo (taxa de recusa elevada), escolha um gatilho:

  • Delay: mostrar após X segundos (por defeito 15 s)
  • Scroll: mostrar após X% de scroll da página (por defeito 40%)
  • Pages: mostrar após X páginas vistas na sessão (por defeito 2)

Cooldown

Se o visitante fechar ou recusar o pedido, um cooldown impede que lhe seja proposto de novo durante N dias (por defeito 7). Isso evita o efeito «popup insistente» que leva os utilizadores a bloquear definitivamente o domínio.

Limite diário e horas de silêncio

  • Max per day: número máximo de notificações enviadas a um mesmo subscritor por dia (por defeito 3). Acima disso, a fila de envio rejeita silenciosamente as mensagens excedentes.
  • Quiet hours: intervalo horário durante o qual nenhuma notificação é entregue. As mensagens enfileiradas durante esse intervalo são reprogramadas para a manhã da primeira janela não silenciosa.

6. Cron: configuração e token

O cron comanda todas as operações diferidas: automatizações, fila de envio, drenagem dos webhooks, limpeza. Deve ser chamado a cada 5 minutos através de um URL HTTP protegido por token.

Token

Um token único é gerado na instalação. Para o obter: DataFirefly Push → Automations, a faixa azul no topo mostra o URL completo a copiar para o seu cron.

Exemplo de cron Linux

*/5 * * * * curl -s "https://asualoja.pt/module/dfpushnotifications/cron?token=O_SEU_TOKEN" > /dev/null

Tarefas executadas a cada tick

  1. Reinicialização dos contadores diários (uma vez por dia, ao passar a meia-noite)
  2. Execução das automatizações com prazo vencido (carrinhos abandonados 1 h / 24 h / 72 h, aniversário, inatividade, novos produtos, pedidos de avaliação programados)
  3. Disparo das campanhas programadas cuja data chegou
  4. Drenagem da fila de envio (até 50 notificações por lote por defeito, configurável)
  5. Drenagem da fila dos webhooks (até 100 por lote)
  6. Limpeza das entradas antigas (sent > 60 dias, registo de webhooks > 30 dias)

A resposta do cron é um JSON que detalha cada etapa:

{
  "success": true,
  "tasks": {
    "reset_counters": "ok",
    "triggers": { "abandoned_1h": 12, "abandoned_24h": 4, "birthday": 2, "inactivity": 38 },
    "scheduled_campaigns": 1,
    "queue": { "processed": 50, "sent": 47, "failed": 2, "expired": 1 },
    "webhooks": { "processed": 8, "sent": 8, "failed": 0, "dropped": 0 },
    "cleanup": "ok"
  },
  "duration_ms": 1842
}

Se o seu alojamento não dispuser de cron, configure um serviço de terceiros gratuito (cron-job.org, EasyCron, cronless) a apontar para o mesmo URL a cada 5 minutos.

7. Automatizações: os 9 gatilhos

Desativadas por defeito, a ativar uma a uma a partir de DataFirefly Push → Automations. Cada cartão mostra o título, o corpo e as estatísticas. Clique em Edit para personalizar o texto e as opções.

Variáveis disponíveis

Consoante o gatilho, pode inserir no título e no corpo:

  • {first_name}: nome próprio do cliente (vazio para os visitantes anónimos)
  • {cart_total}: montante do carrinho abandonado, formatado com a moeda
  • {order_reference}: referência da encomenda
  • {order_total}: montante total da encomenda
  • {product_name}: nome do produto (reposição de stock, descida de preço)
  • {product_price}: preço atual do produto
  • {products_count}: número de novos produtos (resumo)

Carrinho abandonado (3 lembretes)

Três gatilhos independentes: abandoned_cart_1h, abandoned_cart_24h, abandoned_cart_72h. O módulo regista cada alteração de carrinho em ps_dfpush_cart_watch e marca o carrinho como convertido assim que uma encomenda é validada. O cron envia cada lembrete no momento devido, salvo se o carrinho tiver sido convertido entretanto.

Reposição de stock

Na página de produto, um botão Notify me when back in stock aparece automaticamente quando o produto está esgotado. O subscritor clica, o seu opt-in push é pedido se necessário, e o módulo regista depois um watcher em ps_dfpush_product_watch. Assim que uma alteração de stock leva a quantidade disponível acima de 0, o watcher é notificado e marcado como tratado.

Descida de preço

Mesmo princípio com o botão Notify me on price drop. O watcher guarda o preço de referência no momento do opt-in. A notificação é enviada assim que uma atualização de produto faz passar o preço abaixo de 99% do preço de referência (um limiar que evita disparos parasitas nos arredondamentos).

Confirmação de encomenda

Acionada pelo hook actionValidateOrder. Enviada imediatamente, sem respeitar as horas de silêncio (transacional). Ligação direta para a página de detalhe da encomenda.

Expedição

Acionada por actionOrderStatusUpdate assim que o estado passa a um estado marcado como shipped no PrestaShop. Ligação para o detalhe da encomenda (que contém o seguimento se usar um módulo de tracking).

Pedido de avaliação

Programado X dias após a passagem da encomenda a um estado delivery (por defeito 7 dias, configurável no JSON de configuração do gatilho). A notificação é enfileirada com um scheduled_at futuro, e o cron entrega-a quando chega a hora.

Aniversário

O cron lê o campo birthday do cliente PrestaShop e envia a notificação no próprio dia à hora configurada. Um desduplicador evita vários envios no mesmo ano.

Inatividade

Identifica os subscritores cuja last_visit remonta a mais de N dias (por defeito 30). Para evitar o assédio, um mesmo subscritor só é notificado no máximo uma vez a cada 30 dias por este gatilho.

Novos produtos

Resumo diário enviado a uma hora configurável (por defeito 10 h). O módulo agrega os produtos criados nas últimas 24 horas e envia uma notificação que menciona o nome do primeiro e o número total. Ideal para uma loja que acrescenta regularmente catálogo.

8. Construtor de campanhas

Para as operações pontuais: DataFirefly Push → Campaigns → New campaign. O formulário está dividido em cinco secções.

Conteúdo

  • Campaign name: nome interno (nunca apresentado aos subscritores)
  • Notification title: 80 caracteres no máximo
  • Body: 250 caracteres no máximo
  • Click URL: para onde o clique redireciona
  • Icon URL: pequeno logótipo (por defeito o logótipo da sua loja)
  • Large image URL: imagem hero, 1024 × 512 recomendado (apenas Chrome)
  • Badge URL: PNG monocromático 72 × 72 (Android)

Botões de ação

Até dois botões com a sua etiqueta e URL. Aparecem por baixo da notificação no Chrome desktop e no Android. Ideal para propor vários CTA (Ver a oferta / Ignorar).

Audiência

Ver a secção Segmentação abaixo.

Schedule & delivery

  • Send at: data / hora do envio. Vazio = imediato (na próxima drenagem do cron).
  • Urgency: very-low, low, normal, high. Influencia a prioridade do lado do push service.
  • TTL: tempo de vida em segundos (por defeito 86400 = 24 h). Se o navegador do subscritor estiver offline durante mais tempo, a notificação expira.
  • Require interaction: notificação persistente até clique ou fecho manual (apenas Chrome).

9. Segmentação

Combinável com E lógico. Todos os critérios vazios = nenhuma restrição.

Critério Efeito
Languages O subscritor fala pelo menos um destes idiomas (caixas assinaladas)
Countries País detetado na inscrição (baseado no idioma / IP / geo)
Devices mobile / desktop / tablet (detetado na inscrição)
Browsers Chrome, Firefox, Safari, Edge, Opera, Samsung Internet
Customer groups O subscritor está ligado a um cliente PrestaShop em pelo menos um dos grupos
Purchase history Any (por defeito), Has bought, Never bought
Active within N days Última visita há menos de N dias (baseado em ps_dfpush_customer_activity)

O botão Preview audience size calcula em AJAX o número exato de subscritores correspondentes. Útil para verificar que uma segmentação não é demasiado restritiva antes do envio.

10. Testes A/B

Em cada campanha, o campo % of audience for variant B define a parte da audiência que recebe a variante B (de 0 a 50). A distribuição é determinista: para um dado id_subscriber, o subscritor recebe sempre a mesma variante (baseado em id_subscriber % 100 < split).

A variante B só substitui os campos preenchidos. Pode por exemplo mudar apenas o título, ou testar apenas uma imagem. As estatísticas são guardadas separadamente:

  • stats_delivered / stats_clicked / stats_revenue: variante A
  • stats_b_delivered / stats_b_clicked / stats_b_revenue: variante B

As colunas aparecem na lista de campanhas com um emblema A/B ao lado do nome.

11. Atribuição da receita

Mecanismo-chave do módulo: ligar as encomendas às notificações que as originaram.

Fluxo

  1. O módulo envia uma notificação com um track_token único (32 caracteres hex) no payload.
  2. O service worker interceta o clique e redireciona para /module/dfpushnotifications/track?t=TOKEN&click=1&u=URL.
  3. O controlador track coloca um cookie dfpush_attr=TOKEN (30 dias, SameSite=Lax) e redireciona para o URL final.
  4. O cliente navega, adiciona ao carrinho, valida a encomenda.
  5. No hook actionValidateOrder, o AttributionService lê o cookie, encontra a notificação em ps_dfpush_notifications, escreve id_order + revenue + currency na linha.
  6. O serviço incrementa stats_revenue (ou stats_b_revenue consoante a variante) na campanha ou no gatilho, aciona o webhook order.attributed e apaga depois o cookie.

Limites da atribuição

  • Janela fixa de 30 dias. Para além disso, a atribuição deixa de acontecer.
  • Um único cookie por subscritor. Se o utilizador clicar numa segunda notificação antes de encomendar, é a última que é creditada (modelo last click).
  • A atribuição exige que o clique e a encomenda ocorram no mesmo navegador (o cookie está ligado ao navegador).
  • Uma encomenda já atribuída não pode ser reatribuída (o campo id_order > 0 bloqueia a dupla contabilização).

12. Tópicos

Os tópicos são canais de subscrição temáticos que os clientes ativam a partir da sua conta. Exemplo: Promoções, Novos produtos, Alertas de stock. Um subscritor que só assinale Promoções só receberá as campanhas dirigidas a esse tópico.

Criar um tópico

  1. DataFirefly Push → Topics → New topic
  2. Code: identificador interno sem espaços (ex.: flash_deals)
  3. Display order: posição na lista apresentada ao cliente
  4. Active: visível para os clientes
  5. Default opt-in: pré-assinalado no momento da inscrição
  6. Translations: um nome e uma descrição por idioma instalado

Dirigir uma campanha a um tópico

A segmentação inclui um critério Topics no resolvedor. Para o ativar a partir da UI: atualmente apenas através de JSON personalizado (a caixa de verificação Topics chega numa atualização menor). Os subscritores sem nenhum tópico subscrito recebem tudo (retrocompatibilidade).

13. Inbox in-app

O endpoint /module/dfpushnotifications/inbox devolve as 20 últimas notificações do subscritor atual em JSON. O front-office abre esta inbox através da modal unificada acessível a partir da conta de cliente (bloco Push notifications).

A modal mostra também o estado da subscrição (com botão subscribe / unsubscribe) e a lista dos tópicos. Para a chamar manualmente a partir do seu tema:

// Abrir a modal
window.dfpush.openManagePopup();

// Verificar o estado de subscrição
const isOn = window.dfpush.isSubscribed();

14. Webhooks

Os webhooks enviam os eventos do módulo para o Zapier, Make, n8n ou o seu próprio backend. Cada webhook é assinado HMAC-SHA256 sobre o corpo em bruto do pedido.

Criar um webhook

  1. DataFirefly Push → Webhooks → New webhook
  2. URL: o seu endpoint (HTTPS recomendado)
  3. Secret: gerado automaticamente, copie-o do lado do recetor
  4. Events: assinale os eventos a entregar entre os 8 disponíveis
  5. Clique em Send test ping para verificar que o seu endpoint responde 2xx

Eventos disponíveis

  • subscriber.subscribed: novo opt-in
  • subscriber.unsubscribed: cancelamento
  • subscriber.expired: o push service devolveu 410 Gone
  • notification.sent: notificação entregue com sucesso
  • notification.clicked: clique registado
  • notification.failed: falha definitiva após 3 tentativas
  • campaign.sent: campanha terminada
  • order.attributed: encomenda ligada a uma notificação

Formato do payload

{
  "event": "notification.clicked",
  "timestamp": "2026-05-28T14:32:18+00:00",
  "shop": 1,
  "data": {
    "id_subscriber": 482,
    "id_campaign": 12,
    "id_trigger": 0,
    "id_notification": 9182,
    "track_token": "abc123...",
    "url": "https://asualoja.pt/promocoes",
    "ab_variant": "A"
  }
}

Cabeçalhos HTTP enviados

  • Content-Type: application/json
  • X-DfPush-Event: notification.clicked
  • X-DfPush-Signature: sha256=<hex>
  • X-DfPush-Timestamp: 1748443938
  • User-Agent: DataFireflyPush/1.2

Verificar a assinatura do lado do recetor

Exemplo PHP:

$body     = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, $YOUR_SECRET);
$received = explode('=', $_SERVER['HTTP_X_DFPUSH_SIGNATURE'])[1] ?? '';
if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}
// Assinatura válida, tratar o payload
$payload = json_decode($body, true);

Retry e drop

Se o seu endpoint responder algo diferente de 2xx, o módulo tenta de novo com um backoff exponencial até 5 tentativas. Depois disso, o registo é marcado como dropped e o evento é perdido. Os registos sent e dropped são limpos após 30 dias.

15. Multiloja e multilingue

Todos os subscritores, campanhas, automatizações, tópicos e webhooks estão associados a um id_shop. Em multiloja:

  • Selecione a loja alvo no seletor do back-office antes de criar uma campanha ou uma automatização
  • O cron é único mas filtra automaticamente por loja
  • As chaves VAPID são partilhadas entre lojas (um único par para todas)

Do lado dos idiomas: o módulo é entregue em FR, EN, ES, DE e IT. O idioma do subscritor é detetado na inscrição e guardado. Pode segmentar por idioma nas campanhas.

16. RGPD e boas práticas

  • Consentimento: a subscrição assenta no opt-in nativo do navegador, que constitui uma prova de consentimento compatível com o RGPD.
  • Dados pessoais: o módulo guarda o endpoint Web Push, o IP no momento da inscrição, o user-agent, o idioma e o país. Nenhuma transmissão a terceiros.
  • Cancelamento: um clique no botão Unsubscribe da modal ou a desativação das notificações no navegador coloca o subscritor no estado revoked.
  • Direito ao apagamento: a eliminação de uma conta de cliente no BO elimina também os seus subscritores associados.
  • Horas de silêncio: por defeito 22 h – 8 h. Adapte ao seu público (B2B = horário de expediente, B2C = fim do dia).
  • Limite diário: por defeito 3 / dia. Acima disso, taxa de cancelamento muito elevada.

17. Resolução de problemas

O opt-in não aparece

  • Verifique que o seu site está em HTTPS (não HTTP).
  • Verifique que as chaves VAPID foram geradas (Settings).
  • Verifique que o interruptor Push notifications enabled está ativo.
  • Abra a consola do navegador (F12) e procure erros do lado do dfpush-frontend.js.
  • Se já recusou ou ignorou o pedido, o cooldown bloqueia durante N dias. Apague os cookies do domínio para reinicializar, ou mude de navegador para testar.

O cron não é executado

  • Chame o URL manualmente no seu navegador: deverá ver um JSON com success: true. Se vir um 403 invalid_token, o token está mal copiado.
  • Verifique a última execução no painel (Dashboard, bloco System).
  • Em alguns alojamentos, o timeout cURL dos crons é de 30 s. Se a fila for muito grande, aumente a frequência do cron para a cada 1 ou 2 minutos para tratar lotes mais pequenos.

As notificações não partem

  • Separador Queue: se as linhas estão em pending, é porque o cron não correu desde a sua criação.
  • Se estão em failed, clique na linha para ver o código HTTP e a mensagem de erro do push service.
  • 410 Gone = a subscrição já não é válida (o utilizador cancelou ou apagou o seu navegador). O módulo marca automaticamente o subscritor como expired.
  • 429 Too Many Requests = limite de débito do lado do push service. O módulo tenta de novo automaticamente com backoff.

As encomendas não são atribuídas

  • Verifique que os cookies de terceiros não estão bloqueados pelo navegador do cliente (modo privado, alguns anti-trackers).
  • O cookie expira aos 30 dias: uma encomenda feita 31 dias após o clique não será atribuída.
  • Se vir id_order = 0 em ps_dfpush_notifications apesar de a encomenda ter sido feita, verifique que os hooks actionValidateOrder estão registados (Módulos → Hooks → actionValidateOrder).

Erro SQL com “LIMIT 1 LIMIT 1”

Bug interno corrigido na 1.2.0 (Db::getValue e Db::getRow acrescentam automaticamente o seu próprio LIMIT 1). Se ainda vir este erro, verifique que tem a última versão do módulo instalada.

18. FAQ

Quantos subscritores consegue o módulo gerir?

O módulo não tem limite codificado. Na prática, o fator limitante é o tempo de execução do cron: num alojamento partilhado padrão, conte com cerca de 50 envios por minuto (limitado pelos push services). Para 10 000 subscritores, preveja um cron a cada 1 ou 2 minutos durante o envio de uma grande campanha.

O Safari iOS está mesmo excluído?

O Safari iOS suporta o Web Push desde o iOS 16.4, mas apenas para os sites instalados como PWA no ecrã inicial. Num Safari clássico, a API Notification devolve undefined. É uma limitação da Apple, não do módulo.

Posso migrar os meus subscritores do OneSignal ou do Firebase?

Não. Os endpoints push estão ligados ao par de chaves VAPID usado na inscrição. Se mudar de par, as subscrições existentes tornam-se inválidas. Uma migração exigiria uma nova inscrição dos utilizadores.

O módulo funciona no PrestaShop 1.7?

Não, apenas PrestaShop 8.0 a 9.x. A versão 1.7 usa uma arquitetura de administração diferente que exigiria um fork dedicado.

Posso personalizar o service worker?

Sim, o ficheiro views/js/sw-template.js é renderizado pelo controlador swjs.php e pode ser estendido. Atenção: qualquer alteração do service worker exige um novo register() do lado do cliente. Os visitantes antigos manterão a versão anterior até que o navegador detete a alteração (geralmente 24 h).

Como exportar os subscritores?

Separador Subscribers, botão Export CSV. O ficheiro contém endpoint, browser, device, idioma, país, data de inscrição e contadores de envios / cliques.

Suporte

Para qualquer questão não coberta por este guia, contacte o suporte DataFirefly. Para comunicar um bug, junte o detalhe da sua versão PrestaShop, PHP e o conteúdo da resposta JSON do cron.

Esta página foi útil?

Ainda com dúvidas? Contacte o suporte