Opsellio — Guia de Checkout & Pós-Venda
📋 Documento técnico de referência

Checkout & Pós-Venda
Opsellio

Guia completo para os programadores implementarem um checkout de alta conversão — desde os testes iniciais até à entrega do produto a compradores leigos.

M-Pesa e-Mola Cartão de Crédito Apple Pay Google Pay WebView Safari iOS
01

O que testar e melhorar no checkout

Pontos críticos para garantir que o checkout da Opsellio converte ao máximo — cobrindo métodos locais (M-Pesa, e-Mola) e globais (Cartão, Apple Pay, Google Pay).

Impacto por passo extra
−10%
Conversão por step adicional
Meta de passos
≤ 3
Do início ao pagamento
Checkout como convidado
Obrigatório
Nunca forçar registo antes
Carregamento máximo
3s
LCP da página de checkout
Fluxo geral do checkout
Número mínimo de passos Crítico
Testar se o utilizador consegue completar a compra em 3 passos ou menos. Cada passo extra reduz conversão em ~10%.
todos os métodos
🔁
Erro de rede a meio do pagamento Crítico
Simular timeout durante o processamento. O utilizador é informado? Cobrado duas vezes? O estado da compra é correto? Implementar idempotency key em todas as tentativas.
todos os métodos
💾
Persistência do carrinho
Se o utilizador sair e voltar, os dados do produto ainda estão lá? Testar com sessão expirada e em modo anónimo.
todos os métodos
Redirecionamento pós-compra
Após pagamento confirmado, o utilizador chega à página de obrigado/acesso ao curso dentro de 5 segundos? Testar em 3G lento.
todos os métodos
⌨️
Preenchimento automático de dados
Verificar se o autofill do browser funciona nos campos de nome, email e cartão. Campos que bloqueiam autofill perdem conversão especialmente em mobile.
cartão
Pagamentos locais — M-Pesa & e-Mola
⚠️
Atenção crítica: O maior problema invisível é a confirmação de pagamento assíncrona. O webhook do operador pode chegar 10–30 segundos depois — sem polling ou listener, vais mostrar erro a utilizadores que já pagaram.
📱
Validação do número de telefone moçambicano Crítico
Testar com prefixo +258, 258 e sem prefixo. Testar números inválidos e verificar a mensagem de erro. Aceitar: 841234567, 258841234567, +258841234567, +258 84 123 4567.
M-Pesae-Mola
🔔
Confirmação assíncrona com polling Crítico
Se o webhook do operador chega 10–30s depois, o checkout aguarda ou redireciona para página de erro? Implementar polling a cada 5s ou listener de webhook. Só declarar falha após timeout real.
M-Pesae-Mola
🚫
Dupla cobrança na segunda tentativa Crítico
Simular falha seguida de resubmissão. Verificar se o idempotency key está implementado. Cada clique em "Pagar" deve gerar uma nova chave única — o backend rejeita duplicados com a mesma chave.
M-Pesae-Mola
⏱️
Timeout da sessão de pagamento
Se o utilizador não confirmar no telemóvel em 60–120s, o checkout mostra estado de expirado sem bloquear nova tentativa? Testar UX de expiração.
M-Pesae-Mola
💬
Saldo insuficiente — mensagem clara
Quando o utilizador não tem saldo, a mensagem de erro é explicativa ou genérica? "Saldo insuficiente no M-Pesa" converte melhor que "Erro 400". Mapear todos os códigos para mensagens humanas.
M-Pesae-Mola
🕐
Pagamento fora de horário de serviço
M-Pesa e e-Mola têm janelas de manutenção. Testar comportamento do checkout quando o gateway responde com erro de serviço indisponível. Mostrar mensagem adequada ao utilizador.
M-Pesae-Mola
Cartão de crédito — local e internacional
🏦
Cartões moçambicanos (BCI, BIM, Standard Bank) Crítico
Testar com cartões emitidos localmente — frequentemente falham em gateways internacionais por bloqueios do banco emissor. Ter dados de que % de cartões locais falham ajuda a priorizar alternativas.
cartão
🔐
3D Secure / OTP por SMS Crítico
Verificar se o modal de autenticação abre corretamente em WebView, Safari iOS e Chrome Android. 3DS deve abrir via redirect ou iframe — nunca window.open(). Muitos abandonos acontecem neste passo.
cartão
💳
Campos de cartão — formato e máscara
Número do cartão formata com espaços a cada 4 dígitos? Validade aceita MM/AA? CVV oculta os dígitos? Ao fazer paste de número copiado, limpar e formatar automaticamente.
cartão
💬
Cartões recusados — mensagens específicas
Diferenciar: "cartão inválido", "fundos insuficientes", "cartão bloqueado" e "erro do banco". Mensagens genéricas como "pagamento recusado" aumentam o abandono sem dar solução.
cartão
Apple Pay & Google Pay
👁️
Deteção de disponibilidade Crítico
Apple Pay só aparece em Safari/iOS. Google Pay funciona em Chrome/Android. O botão não deve aparecer em contextos não suportados — gera confusão e desconfiança. Detetar via JS antes de renderizar.
Apple PayGoogle Pay
📱
Teste em dispositivo real Crítico
Emuladores não validam Apple Pay. Testar obrigatoriamente em iPhone físico com Safari e Android físico com cartão registado na wallet. BrowserStack permite acesso a dispositivos reais.
Apple PayGoogle Pay
🍎
Apple Pay — domínio verificado na Apple Developer Console
Apple Pay só funciona se o domínio está registado na Apple Developer Console com ficheiro de verificação acessível em /.well-known/apple-developer-merchantid-domain-association.
Apple Pay
🛍️
Desligar recolha de endereço físico nas wallets
Cursos são produtos digitais — não precisam de endereço de entrega. Remover estes campos do payload da wallet. Campos desnecessários aumentam fricção e podem impedir a conclusão da compra.
Apple PayGoogle Pay
UX & confiança durante o checkout
🛡️
Resumo do produto sempre visível Crítico
Nome do curso, valor e o que o utilizador vai receber devem estar visíveis durante todo o fluxo de pagamento — sem necessidade de scroll. Dúvida sobre o que está a comprar = abandono.
Estado de loading após clicar em "Pagar" Crítico
Após clicar em pagar, o botão deve mudar de estado: spinner + texto "A processar…". Sem feedback visual, utilizadores clicam várias vezes — causando tentativas duplicadas e potencial dupla cobrança.
🔒
Indicadores de segurança visíveis
Cadeado SSL, logos de pagamento (Visa, Mastercard, M-Pesa) e texto "Pagamento seguro" visíveis sem scroll. Cupão deve ser escondido por defeito — campo visível faz utilizadores sem cupão procurarem um antes de pagar.
🌐
Exibição correta de MZN vs USD
Para M-Pesa/e-Mola usar MZN. Para cartão internacional pode ser USD. Testar que a moeda exibida corresponde ao método selecionado. Se há conversão, mostrar a taxa usada.
02

Compatibilidade & tráfego pago

Com tráfego pago (Google Ads, Meta Ads), os utilizadores chegam de browsers e contextos específicos. Cada fonte de tráfego tem o seu ambiente de browser — e os seus bugs únicos.

Prioridade máxima
Chrome + Safari
~85% tráfego móvel
Risco Google Ads
Chrome Android
Maior fonte de cliques pagos
Risco Meta Ads
WebView iOS
Instagram/Facebook in-app
Maior ponto cego
Safari iOS
3DS + Apple Pay quirks
🚨
O maior ponto cego: Quando um utilizador clica num anúncio do Instagram ou Facebook, não abre no Safari nem no Chrome — abre num browser in-app (WebView) com capacidades reduzidas. Apple Pay não funciona aqui. 3DS falha silenciosamente. É a maior causa invisível de conversões perdidas com Meta Ads.
C
Chrome Android Crítico
~45% do tráfego pago móvel — destino principal Google Ads
Principal destino de anúncios Google (Android é dominante em Moçambique). Qualquer bug aqui queima o orçamento de ads diretamente.
Autofill de cartão via Google Pay
Chrome Android oferece autofill nativo de cartão. Verificar se o formulário aceita — os atributos name e autocomplete nos campos devem estar corretos (cc-number, cc-exp, cc-csc).
Teclado numérico em campos de pagamento
inputmode="numeric" nos campos de telefone (M-Pesa/e-Mola) e número de cartão. Sem isto o utilizador recebe teclado de texto — fricção desnecessária em mobile.
/* Campos de pagamento */ <input type="tel" inputmode="numeric" /> /* M-Pesa */ <input type="text" inputmode="numeric" /> /* Cartão */
Modal 3DS não bloqueado pelo browser
Chrome Android bloqueia popups por padrão. O 3DS deve abrir via redirect ou iframe — nunca via window.open(). Testar com cartão que obriga 3DS.
S
Safari iOS Crítico
~30% do tráfego pago iOS — fonte principal de Meta Ads em iPhone
Safari tem restrições únicas de cookies (ITP), storage e 3DS que outros browsers não têm. Um checkout que funciona no Chrome Android pode falhar completamente aqui.
3DS em iframe — bloqueio de cookies Safari Crítico
Safari bloqueia cookies de terceiros por padrão. Se o 3DS usa iframe de domínio diferente com cookies de sessão, vai falhar silenciosamente. Usar solução de 3DS que não dependa de cookies cross-domain.
Viewport com barra de endereço dinâmica
Safari iOS tem barra de URL que aparece/desaparece. O botão "Pagar" pode ficar tapado. Usar 100dvh em vez de 100vh para altura de viewport.
/* Substituir: */ height: 100vh; /* Por: */ height: 100dvh; /* dynamic viewport height */
ITP — Intelligent Tracking Prevention
Safari bloqueia localStorage entre domínios e limita cookies a 7 dias. Se o carrinho usa storage cross-domain vai quebrar. Testar fluxo completo em Safari iOS em modo privado.
W
WebView iOS / Android Crítico
Destino direto de Meta Ads (Instagram, Facebook) — browser in-app
Não é o Safari nem o Chrome. É um browser embutido com capacidades reduzidas e sem acesso às wallets nativas.
Apple Pay desativado no WebView Crítico
Apple Pay NÃO funciona em WebViews — nem no iOS. O botão deve ser escondido ou substituído por "Abrir no Safari" quando WebView for detetado.
/* Deteção de WebView */ const isWebView = /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/i .test(navigator.userAgent) || /FB_IAB|FB4A|FBAN/i.test(navigator.userAgent); if (isWebView) { hideApplePay(); showOpenInBrowserBanner(); }
Banner "Abrir no Chrome/Safari" Crítico
Implementar deteção de WebView e mostrar banner: "Para melhor experiência de pagamento, abre no Chrome ou Safari". Salva conversões que de outra forma seriam perdidas por limitações técnicas do WebView.
Redirecionamento 3DS no WebView
WebViews frequentemente bloqueiam redirecionamentos de terceiros usados no fluxo 3DS. Testar com cartões que obrigam 3DS (a maioria dos cartões moçambicanos).
Cenários críticos por fonte de tráfego
Google Search Ads
Clique no anúncio → Chrome Android
Fluxo mais comum. Testar o tempo total do fluxo em Chrome Android com 3G simulado. Cada segundo extra de carregamento custa ~7% de conversão. Meta: checkout carregado em menos de 3 segundos em 3G.
Instagram Story Ads
Clique na story → WebView iOS
Apple Pay não vai funcionar. Testar se o checkout deteta WebView e adapta os métodos de pagamento mostrados. M-Pesa deve ser o método primário destacado neste contexto.
Facebook Feed Ads
Clique no feed → WebView Android
Grande volume de tráfego. Google Pay pode falhar no WebView Android. M-Pesa e e-Mola devem ser os fallbacks primários. Testar fluxo completo no Facebook in-app browser no Android.
Remarketing
Utilizador que já adicionou ao carrinho
Utilizador clicou num anúncio de remarketing. Deve retomar o checkout com o produto já carregado e o email já preenchido. Testar que o estado do carrinho persiste após vir de ad com parâmetros UTM.
Stack de ferramentas de teste recomendada
🖥️
BrowserStack ou LambdaTest
Testar em dispositivos reais na cloud sem ter os dispositivos fisicamente. Imprescindível para Safari iOS e WebViews. Plano pago que se justifica dado o custo de ads desperdiçados.
🔧
Chrome DevTools — Device Emulation + Network Throttling
Para testes rápidos de layout mobile. Usar throttling de rede "3G Slow" para simular condições de Moçambique. Não substitui dispositivo real mas cobre 80% dos casos de forma rápida.
📊
Meta Pixel Helper + Google Tag Assistant
Verificar que os eventos InitiateCheckout e Purchase estão a disparar corretamente. O evento de compra deve disparar depois do pagamento confirmado — nunca antes. Testar em Safari iOS onde o ITP pode bloquear os pixels.
WebPageTest.org — performance em África
Testar performance do checkout a partir de localização em África com perfil de rede 3G. Ver onde está o bottleneck de carregamento. Meta: LCP abaixo de 3 segundos em 3G.
03

Zero fricção nos campos de checkout

Os atributos certos, validação inteligente e formatação automática fazem a diferença entre um formulário que converte e um que frustra.

Sem otimização — mata conversão
autocomplete="off" em todos os campos
type="text" em campos numéricos
Placeholder como único label
Sem inputmode definido
Erros só visíveis ao submeter
Formulário limpo ao dar erro
Campos desnecessários (morada, CP)
Otimizado — checkout escorregadio
autocomplete semântico por campo
type e inputmode corretos
Label visível + placeholder
inputmode="numeric" em campos certos
Validação inline onBlur
Dados preservados após erro
Apenas: nome, email, pagamento
Atributos HTML por campo — mapa completo
🚫
NUNCA usar autocomplete="off" Crítico
Bloqueia o autofill do browser, do gestor de passwords e do Google Pay/Apple Pay. É um dos maiores redutores de conversão — especialmente em mobile onde digitar é difícil.
/* NUNCA fazer: */ <input autocomplete="off"> /* SEMPRE especificar: */ <input name="email" autocomplete="email"> <input name="name" autocomplete="name">
📱
Telefone M-Pesa/e-Mola — teclado numérico Crítico
type="tel" com inputmode="numeric" abre o teclado numérico em iOS e Android. Pré-preencher "+258" como prefixo fixo reduz erros de formato e steps de digitação.
<label for="phone">Número M-Pesa / e-Mola</label> <input id="phone" type="tel" name="phone" autocomplete="tel" inputmode="numeric" placeholder="+258 84 000 0000">
💳
Número de cartão — autofill semântico Alto
name="cc-number" e autocomplete="cc-number" fazem o browser e gestores de password reconhecer e preencher automaticamente. Inserir espaço a cada 4 dígitos automaticamente via JS.
<input type="text" name="cc-number" autocomplete="cc-number" inputmode="numeric" placeholder="0000 0000 0000 0000" maxlength="19"> <input type="text" name="cc-exp" autocomplete="cc-exp" inputmode="numeric" placeholder="MM/AA"> <input type="password" name="cc-csc" autocomplete="cc-csc" inputmode="numeric" placeholder="CVV">
🏷️
Label visível em todos os campos Alto
Placeholder desaparece ao digitar — o utilizador perde o contexto. Cada campo precisa de um <label> visível, mesmo que mais pequeno. Nunca usar só placeholder como label.
Validação — regras que evitam abandono
Validação inline — onBlur, não onSubmit Crítico
Mostrar erro ao sair do campo (onBlur), não só quando clica em Pagar. O utilizador corrige em contexto imediato em vez de ter que encontrar o erro depois de submeter tudo.
📞
Telefone — aceitar múltiplos formatos Crítico
Aceitar: 841234567, 258841234567, +258841234567, +258 84 123 4567. Normalizar no backend — nunca rejeitar formatos válidos. Utilizadores copiam números do WhatsApp em formatos variados.
🚫
Nunca apagar o valor ao mostrar erro Crítico
Se o email está errado, manter o valor escrito e sublinhar o erro. Apagar o campo obriga o utilizador a reescrever tudo — é uma das maiores causas de frustração e abandono.
💳
Número de cartão — validar com algoritmo Luhn Alto
Validação básica de 16 dígitos não chega. Usar o algoritmo de Luhn no frontend para apanhar erros de digitação antes de ir ao gateway — poupa uma chamada de rede e dá feedback imediato.
💬
Mensagens de erro em português claro Alto
"Campo obrigatório" é fraco. Usar: "Introduz o teu email para receber o acesso ao curso" ou "Número de telefone moçambicano inválido — deve começar por 84, 85, 86 ou 87".
Feedback positivo — ícone de confirmação
Após preencher um campo corretamente, mostrar um visto verde. Reforço positivo reduz a ansiedade no checkout e sinaliza progresso. O botão de pagar só ativa quando todos os campos estão válidos.
Técnicas de redução de fricção
🎯
Eliminar campos desnecessários Crítico
Para cursos (produto digital): NÃO pedir morada, cidade, código postal. Pedir apenas: nome, email e método de pagamento. Cada campo extra é uma razão para abandonar.
👤
Checkout como convidado — não obrigar registo Crítico
Permitir pagar sem criar conta. Criar conta pode ser oferecido DEPOIS do pagamento confirmado. Obrigar registo antes do pagamento é um dos maiores redutores de conversão conhecidos.
🏷️
Campo de cupão escondido por defeito Crítico
Mostrar "Tens um cupão?" como link expandível. Um campo visível faz utilizadores sem cupão sentirem que estão a pagar mais do que deviam e saírem à procura de um código.
💳
Formatação automática do número de cartão Alto
Inserir espaço a cada 4 dígitos automaticamente. Ao fazer paste de número copiado (com ou sem espaços), limpar e formatar. Após 16 dígitos, focar automaticamente no campo de validade.
// Formatação automática input.addEventListener('input', (e) => { let v = e.target.value.replace(/\D/g, '').slice(0, 16); e.target.value = v.replace(/(.{4})/g, '$1 ').trim(); if (v.length === 16) expInput.focus(); // Avançar campo });
🔍
Deteção automática da bandeira do cartão Médio
Ao digitar os 4 primeiros dígitos mostrar logo Visa/Mastercard. 4xxx = Visa, 5xxx = Mastercard. Confirma visualmente ao utilizador que o tipo de cartão é aceite.
📲
Tamanho mínimo de área de toque — 44px
Todos os botões, checkboxes e links no checkout devem ter pelo menos 44×44px de área clicável (padrão Apple HIG). Evita mis-taps em mobile que frustram e aumentam o abandono.
04

Recuperar vendas após falha de pagamento

Um utilizador que chegou ao checkout já tomou a decisão de comprar. O erro não desfez essa decisão — apenas criou um obstáculo. O objetivo é remover esse obstáculo enquanto a intenção está quente.

Erros recuperáveis
~70%
Com a mensagem certa
Abandono sem recovery
~65%
Sem sistema de recuperação
Recuperação por email
15–25%
Sequência bem executada
No momento do erro — o que implementar
💾
Não limpar o formulário quando o pagamento falha Crítico
O utilizador já preencheu nome, email, dados do cartão. Apagar tudo ao falhar é a forma mais rápida de perder a venda. Manter tudo preenchido e mostrar apenas a mensagem de erro.
📧
Capturar email antes de processar o pagamento Crítico
Assim que o utilizador preenche o email e avança para o passo seguinte, guardar no backend (POST /checkout/initiate com email + produto_id). Se o pagamento falhar, tens o contacto para recuperação.
// Guardar email imediatamente ao avançar de step async function onEmailStepComplete(email, productId) { await fetch('/api/checkout/initiate', { method: 'POST', body: JSON.stringify({ email, productId, timestamp: Date.now() }) }); // Avançar para o próximo passo }
🔀
Sugerir método alternativo imediatamente Crítico
Logo abaixo da mensagem de erro, mostrar os outros métodos disponíveis. Se o cartão falhou → mostrar M-Pesa e e-Mola. Não obrigar o utilizador a voltar atrás para mudar o método.
💬
Mensagem de erro específica por tipo de falha Crítico
Nunca mostrar "Pagamento recusado" genérico. Mapear códigos do gateway para mensagens humanas: "O teu banco recusou — tenta M-Pesa" ou "Saldo insuficiente na conta M-Pesa".
🔢
Contador de tentativas — não bloquear prematuramente Alto
Permitir pelo menos 3 tentativas antes de qualquer bloqueio. Mostrar "Tentativa 1 de 3" para criar urgência positiva. Só bloquear se houver risco real de fraude (padrões suspeitos).
💬
WhatsApp de suporte acessível no ecrã de erro Alto
Botão de contacto direto no ecrã de erro. No contexto moçambicano, WhatsApp resolve problemas mais rapidamente que email. Um utilizador que chegou ao checkout quer comprar — ajudá-lo a resolver converte.
🎁
Cupão de desconto no segundo erro Médio
Se o utilizador falha duas vezes, oferecer automaticamente 10–15% de desconto: "Sabemos que está a ter problemas — aqui está um código especial para facilitar." Recupera vendas de utilizadores frustrados.
Design dos ecrãs de erro — exemplos
O teu banco recusou o pagamento
Isto acontece quando o cartão não tem saldo suficiente, está bloqueado para compras online, ou o banco precisa de autorização. O teu cartão não foi cobrado.
O que tentaste comprar
Curso: [Nome do Curso]
1.500 MT
Ou paga com outro método
M-Pesa (84/85/86...)
e-Mola (87...)
O pagamento expirou sem confirmação
Não recebemos a confirmação do teu M-Pesa a tempo. Não te preocupes — não foste cobrado. Podes tentar novamente agora.
O que tentaste comprar
Curso: [Nome do Curso]
1.500 MT
Ou tenta outro método
Cartão de crédito
e-Mola
Sequência de email de recuperação
💡
Timing é tudo: Os primeiros 15 minutos são os mais críticos — a intenção de compra ainda está quente. Não oferecer desconto logo no Email 1 — isso treina utilizadores a esperar por descontos.
15 minutos após erro
Email 1 — "O teu acesso ao [Curso] ainda está reservado"
Tom empático, sem drama. Não mencionar o erro técnico. Mostrar o produto com botão direto para checkout com sessão restaurada. Listar os métodos de pagamento disponíveis.
2 horas após erro
Email 2 — "Tens dificuldades a pagar? Podemos ajudar"
Se não abriu o primeiro email. Tom útil e prático: "Se tiveste problemas com o cartão, podes pagar por M-Pesa ou e-Mola" + link WhatsApp de suporte.
24 horas após erro
Email 3 — Social proof + urgência + desconto 10%
Depoimento de um aluno + lembrete do que vai aprender. Aqui pode aparecer um código de desconto de 10% com validade de 48h. Nunca oferecer desconto antes — treina mau comportamento.
48 horas após erro
Email 4 — "Última oportunidade para garantir o preço"
Só usar urgência real — nunca falsa. "A tua reserva expira hoje" ou "O preço promocional termina amanhã". Só enviar se houver escassez genuína.
7 dias após erro
Email 5 — Reengagement de longo prazo
Sair da sequência de erro e entrar no nurturing normal. Enviar conteúdo gratuito relacionado com o tema do curso. Manter o relacionamento para futura conversão.
Implementação técnica — checklist
🔑
Idempotency key por tentativa Crítico
Cada clique em "Pagar" gera uma chave única. O backend rejeita duplicados com a mesma chave — evita cobranças duplas em caso de retry do browser ou cliques múltiplos.
// Frontend — gerar chave por tentativa const idempotencyKey = `${userId}-${productId}-${Date.now()}`; // Backend — verificar antes de processar if (await redis.get(`payment:${idempotencyKey}`)) { return { status: 'already_processed' }; } await redis.set(`payment:${idempotencyKey}`, 'processing', 'EX', 300);
🔄
Webhook com retry automático (backoff exponencial) Crítico
Se o webhook do operador (M-Pesa, gateway) falhar, implementar retry com backoff: 30s → 2min → 10min → 1h. Nunca depender de um único disparo para confirmar pagamento.
📊
Log de erros com contexto completo Alto
Para cada falha guardar: user_id, produto_id, método, código de erro do gateway, timestamp, número de tentativa. Sem este log é impossível identificar padrões (ex: "cartões BCI falham 80%").
🔗
Link de checkout com sessão restaurada Alto
O link no email de recuperação deve restaurar o carrinho com o produto pré-carregado e o email já preenchido. Não mandar o utilizador para a homepage — o clique deve abrir diretamente no passo de pagamento.
05

Entregar o produto a compradores leigos

~40% dos compradores de cursos online nunca acede ao produto que comprou. Não por falta de interesse — mas por encontrar um obstáculo no primeiro acesso. Para utilizadores leigos este número é ainda mais alto.

Abandono pós-compra
~40%
Nunca acede ao curso
Dúvida mais comum
"Onde fica?"
Sem instruções claras
Melhor canal suporte MZ
WhatsApp
Taxa de resposta muito maior
⚠️
O maior problema não é a plataforma — é o comprador leigo não saber o que fazer a seguir. A entrega começa na página de confirmação, não no email. Se o utilizador fechar essa página sem saber o próximo passo, a probabilidade de nunca mais voltar é muito alta.
Entrega imediata — os primeiros 5 minutos
📋
Página de confirmação com instrução de 3 passos Crítico
Em vez de apenas "Obrigado pela compra", mostrar literalmente: Passo 1 — Verifica o teu email. Passo 2 — Clica no link para criar a tua senha. Passo 3 — Acede ao curso. Utilizadores leigos precisam de ser conduzidos explicitamente.
🔗
Link de acesso direto — magic link, não login separado Crítico
O link no email de boas-vindas deve fazer login automático (magic link) e abrir diretamente no curso. Evitar: clica no link → página de login → esqueci senha → desistência total.
// Gerar magic link ao criar a compra const token = crypto.randomBytes(32).toString('hex'); await db.magicLinks.create({ token, userId, expiresAt: Date.now() + 7 * 24 * 3600 * 1000 }); const magicUrl = `https://opsellio.com/aceder?token=${token}&curso=${courseId}`;
📱
SMS/WhatsApp de confirmação para M-Pesa e e-Mola Crítico
Compradores via M-Pesa muitas vezes não monitorizam o email. Enviar SMS ou mensagem WhatsApp com o link de acesso é essencial para este segmento no contexto moçambicano. WhatsApp tem taxa de leitura acima de 90%.
Email de acesso nos primeiros 2 minutos Crítico
O email com o link de acesso deve chegar em menos de 2 minutos. Acima disso o utilizador já está a perguntar "Onde está o meu curso?". Usar serviço de email transacional (Resend, SendGrid, Mailgun) — nunca SMTP próprio.
🎯
Botão de acesso imediato na página de confirmação Alto
Se o utilizador já tem conta criada, dar acesso direto ao curso na própria página de confirmação — sem precisar do email. Um clique e está dentro. O email é reforço, não único canal.
📁
Guardar o acesso na conta — área "Os meus cursos" Alto
O utilizador deve encontrar o curso na área pessoal da plataforma sem depender de encontrar o email original. Emails perdem-se e vão para spam — a conta é a fonte de verdade.
Emails transacionais — estrutura recomendada
💡
Regra de ouro para utilizadores leigos: Um único CTA por email. Instruções em passos numerados, não em prosa. Nunca usar linguagem técnica ("área de membros", "dashboard", "plataforma LMS").
Fluxo de onboarding na plataforma
Ecrã 1 — imediato após login
Boas-vindas personalizada + 1 botão
"Bem-vindo/a, [Nome]! O teu curso [Nome] está pronto." Com imagem do curso. Um único botão: "Começar agora". Sem menus, sem distrações neste primeiro ecrã.
Objetivo: criar o momento "uau" imediato que confirma que a compra valeu a pena.
Ecrã 2 — antes da primeira aula
Orientação de 3 pontos — o que esperar
Mostrar brevemente: quantas aulas tem o curso, quanto tempo por aula, e o que vai conseguir fazer no final. Formato visual simples — nunca texto corrido. Botão: "Percebo, vamos começar".
Não fazer tour à plataforma. O utilizador quer o curso, não um tutorial ao software.
Primeira aula
Vídeo de introdução — máximo 2 minutos
O formador aparece, cumprimenta, explica o que vão aprender e diz "na próxima aula vamos ver X". Tom amigável e direto. Este vídeo é o momento em que o utilizador decide se vai continuar.
Qualidade de áudio importa mais que qualidade de vídeo. Voz clara e nítida é inegociável.
Após 1ª aula
Micro-celebração de conclusão
Mostrar: "Concluíste a primeira aula! Estás a X% do curso." Com botão para a próxima aula imediatamente visível. A primeira conclusão cria o hábito de continuar.
Após registo
Oferecer lembretes — não obrigar
"Queres que te lembremos de estudar?" com opção de dia e hora. Envio por WhatsApp ou SMS. Não obrigar mas oferecer como valor adicional — utilizadores leigos beneficiam muito de lembretes.
Dia 7 sem progresso
Check-in humano por WhatsApp
Se o utilizador não abriu nenhuma aula em 7 dias, enviar WhatsApp pessoal (não email): "Olá [Nome], vimos que ainda não começaste o [Curso]. Tens alguma dificuldade a aceder?" Suporte proativo, não marketing.
Uma mensagem humana aqui recupera uma percentagem surpreendente de utilizadores que se perderam no onboarding.
Sistema de suporte proativo
💬
WhatsApp Business como canal principal Crítico
No contexto moçambicano, WhatsApp é onde os utilizadores se sentem mais confortáveis para pedir ajuda. Email de suporte deve existir mas WhatsApp é prioritário para compradores leigos. Taxa de leitura: >90%.
📡
Detetar inatividade e agir antes do reembolso Crítico
7 dias sem acesso → trigger WhatsApp. 14 dias sem acesso → trigger com oferta de onboarding assistido. Agir antes do chargeback ou pedido de reembolso. Custo de retenção << custo de reembolso.
// Verificar inatividade diariamente SELECT user_id, course_id, last_access FROM enrollments WHERE last_access < NOW() - INTERVAL '7 days' AND completed_at IS NULL; -- Disparar WhatsApp para cada resultado
FAQ integrado na plataforma Alto
Dúvidas mais comuns: "Como acedo?", "Esqueci a senha", "Não recebo o email", "Posso ver no telemóvel?". Devem ter resposta dentro da plataforma — acessível sem sair do curso.
🎬
Tutorial em vídeo de como aceder Alto
Vídeo de 3 minutos a mostrar: como fazer login, encontrar o curso e ver a primeira aula. Partilhar no email de boas-vindas. Utilizadores leigos preferem ver do que ler instruções.
Botão de ajuda sempre visível na plataforma Alto
Botão de chat ou WhatsApp fixo durante a visualização das aulas. Se o utilizador tiver dificuldade técnica, o suporte está a um toque. Nunca esconder o suporte no rodapé.
👥
Grupo WhatsApp de alunos por curso Médio
Para cursos com múltiplos alunos, criar um grupo WhatsApp. Alunos ajudam-se mutuamente, cria comunidade, reduz carga de suporte individual e aumenta a taxa de conclusão. Formador aparece semanalmente.
📊
NPS simples após primeira semana Médio
Uma pergunta única 7 dias após compra: "De 0 a 10, recomendarias este curso a um amigo?" Respostas abaixo de 7 disparam contacto manual de suporte. Dados para melhorar o produto continuamente.
Opsellio.
Guia de Checkout & Pós-Venda — Referência para programadores
5 secções · M-Pesa · e-Mola · Cartão · Apple Pay · Google Pay