O PWA do MishiPay aumenta as transações em 10 vezes e economiza 2,5 anos de filas

Saiba como a mudança para o PWA ajudou os negócios da MishiPay.

O MishiPay permite que os compradores digitalizem e paguem pelas compras com smartphones, em vez de perder tempo na fila do caixa. Com a tecnologia Scan & Go do MishiPay, os compradores podem usar o próprio smartphone para escanear o código de barras dos itens e pagar por eles, e depois simplesmente sair da loja. Estudos revelam que as filas na loja custam ao setor de varejo global cerca de US$ 200 bilhões por ano.

Nossa tecnologia depende de recursos de hardware do dispositivo, como sensores de GPS e câmeras, que permitem que os usuários localizem lojas com suporte para MishiPay, leiam códigos de barras de itens na loja física e paguem usando a forma de pagamento digital de escolha. As versões iniciais da nossa tecnologia Scan & Go eram aplicativos específicos para iOS e Android, e os primeiros usuários adoraram a tecnologia. Leia para saber como a migração para um PWA aumentou as transações em 10 vezes e economizou 2,5 anos de filas.

    10×

    Mais transações

    2,5 anos

    Fila salva

Desafio

Os usuários acham nossa tecnologia extremamente útil ao esperar em uma fila ou fila de check-out, porque ela permite que eles pulem a fila e tenham uma experiência tranquila na loja. No entanto, a dificuldade de fazer o download de um aplicativo Android ou iOS fez com que os usuários não escolhessem nossa tecnologia, apesar do valor. Era um desafio crescente para a MishiPay, e precisávamos aumentar a adoção do usuário com uma barreira de entrada menor.

Solução

Nossos esforços para criar e lançar a PWA nos ajudaram a eliminar a dificuldade de instalação e incentivaram novos usuários a testar nossa tecnologia em uma loja física, pular a fila e ter uma experiência de compra integrada. Desde o lançamento, observamos um aumento significativo na adoção do usuário com nossa PWA em comparação com nossos aplicativos específicos para plataforma.

Comparação lado a lado entre iniciar diretamente o PWA (à esquerda, mais rápido) com a instalação e inicialização do app Android (à direita, mais lenta).
Transações por plataforma. ¡OS: 16.397 (3,98%). Android: 13.769 (3,34%). Web: 382184 (92,68%).
A maioria de todas as transações acontece na Web.

Aprofundamento técnico

Como encontrar lojas com suporte para o MishiPay

Para ativar esse recurso, usamos a API getCurrentPosition() com uma solução substituta baseada em IP.

const geoOptions = {
  timeout: 10 * 1000,
  enableHighAccuracy: true,
  maximumAge: 0,
};

window.navigator.geolocation.getCurrentPosition(
  (position) => {
    const cords = position.coords;
    console.log(`Latitude :  ${cords.latitude}`);
    console.log(`Longitude :  ${cords.longitude}`);
  },
  (error) => {
    console.debug(`Error: ${error.code}:${error.message}`);
    /**
     * Invoke the IP based location services
     * to fetch the latitude and longitude of the user.
     */
  },
  geoOptions,
);

Essa abordagem funcionou bem nas versões anteriores do app, mas depois se mostrou um grande problema para os usuários do MishiPay pelos seguintes motivos:

  • Imprecisões de localização nas soluções de substituição baseadas em IP.
  • Uma listagem crescente de lojas ativadas para o MishiPay por região exige que os usuários rolem a lista e identifiquem a loja correta.
  • Os usuários às vezes escolhem a loja errada, fazendo com que as compras sejam registradas incorretamente.

Para resolver esses problemas, incorporamos QR codes com geolocalização exclusiva nas telas de cada loja. Isso facilitou a integração. Os usuários só precisam ler os códigos QR geolocalizados impressos nos materiais de marketing presentes nas lojas para acessar o aplicativo da Web Scan &Go. Dessa forma, eles não precisam digitar o endereço da Web mishipay.shop para acessar o serviço.

Experimente a leitura de código na loja usando o PWA.

Como ler códigos de barras

Um recurso principal do app MishiPay é a leitura de código de barras, que permite que nossos usuários leiam as próprias compras e vejam o total antes mesmo de chegar ao caixa.

Para criar uma experiência de leitura na Web, identificamos três camadas principais.

Diagrama mostrando as três camadas principais da linha de execução: fluxo de vídeo, camada de processamento e camada do decodificador.

Stream de vídeo

Com a ajuda do método getUserMedia(), podemos acessar a câmera traseira do usuário com as restrições listadas abaixo. Invocar o método aciona automaticamente uma solicitação para que os usuários aceitem ou neguem o acesso à câmera. Assim que tivermos acesso ao stream de vídeo, podemos retransmiti-lo para um elemento de vídeo, conforme mostrado abaixo:

/**
 * Video Stream Layer
 * https://developer.mozilla.org/docs/Web/API/MediaDevices/getUserMedia
 */
const canvasEle = document.getElementById('canvas');
const videoEle = document.getElementById('videoElement');
const canvasCtx = canvasEle.getContext('2d');
fetchVideoStream();
function fetchVideoStream() {
  let constraints = { video: { facingMode: 'environment' } };
  if (navigator.mediaDevices !== undefined) {
    navigator.mediaDevices
      .getUserMedia(constraints)
      .then((stream) => {
        videoEle.srcObject = stream;
        videoStream = stream;
        videoEle.play();
        // Initiate frame capture - Processing Layer.
      })
      .catch((error) => {
        console.debug(error);
        console.warn(`Failed to access the stream:${error.name}`);
      });
  } else {
    console.warn(`getUserMedia API not supported!!`);
  }
}

Camada de processamento

Para detectar um código de barras em um determinado stream de vídeo, precisamos capturar frames periodicamente e transferi-los para a camada do decodificador. Para capturar um frame, basta desenhar os streams de VideoElement em um HTMLCanvasElement usando o método drawImage() da API Canvas.

/**
 * Processing Layer - Frame Capture
 * https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas
 */
async function captureFrames() {
  if (videoEle.readyState === videoEle.HAVE_ENOUGH_DATA) {
    const canvasHeight = (canvasEle.height = videoEle.videoHeight);
    const canvasWidth = (canvasEle.width = videoEle.videoWidth);
    canvasCtx.drawImage(videoEle, 0, 0, canvasWidth, canvasHeight);
    // Transfer the `canvasEle` to the decoder for barcode detection.
    const result = await decodeBarcode(canvasEle);
  } else {
    console.log('Video feed not available yet');
  }
}

Para casos de uso avançados, essa camada também realiza algumas tarefas de pré-processamento, como recorte, rotação ou conversão para escala de cinza. Essas tarefas podem exigir muito da CPU e fazer com que o aplicativo não responda, já que a leitura de código de barras é uma operação de longa duração. Com a ajuda da API OffscreenCanvas, podemos transferir a tarefa que exige muito da CPU para um worker da Web. Em dispositivos com suporte à aceleração gráfica de hardware, a API WebGL e o WebGL2RenderingContext podem otimizar os ganhos nas tarefas de pré-processamento que exigem muito da CPU.

Camada de decodificador

A camada final é a camada de decodificador, que é responsável por decodificar os códigos de barras dos frames capturados pela camada de processamento. Graças à API Shape Detection (que ainda não está disponível em todos os navegadores), o próprio navegador decodifica o código de barras de um ImageBitmapSource, que pode ser um elemento img, um elemento SVG image, um elemento video, um elemento canvas, um objeto Blob, um objeto ImageData ou um objeto ImageBitmap.

Diagrama mostrando as três camadas principais da linha de execução: transmissão de vídeo, camada de processamento e API Shape Detection.

/**
 * Barcode Decoder with Shape Detection API
 * https://web.dev/shape-detection/
 */
async function decodeBarcode(canvas) {
  const formats = [
    'aztec',
    'code_128',
    'code_39',
    'code_93',
    'codabar',
    'data_matrix',
    'ean_13',
    'ean_8',
    'itf',
    'pdf417',
    'qr_code',
    'upc_a',
    'upc_e',
  ];
  const barcodeDetector = new window.BarcodeDetector({
    formats,
  });
  try {
    const barcodes = await barcodeDetector.detect(canvas);
    console.log(barcodes);
    return barcodes.length > 0 ? barcodes[0]['rawValue'] : undefined;
  } catch (e) {
    throw e;
  }
}

Para dispositivos que ainda não oferecem suporte à API Shape Detection, precisamos de uma solução alternativa para decodificar os códigos de barras. A API Shape Detection expõe um método getSupportedFormats() que ajuda a alternar entre a API Shape Detection e a solução substituta.

// Feature detection.
if (!('BarceodeDetector' in window)) {
  return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
  supportedFormats.forEach((format) => console.log(format));
});

Diagrama de fluxo mostrando como, dependendo do suporte ao Detector de código de barras e dos formatos compatíveis, a API Shape Detection ou a solução substituta está sendo usada.

Solução substituta

Várias bibliotecas de verificação corporativas e de código aberto estão disponíveis e podem ser facilmente integradas a qualquer aplicativo da Web para implementar a verificação. Confira algumas das bibliotecas recomendadas pela MishiPay.

Nome da biblioteca Tipo Solução Wasm Formatos de código de barras
QuaggaJs Código aberto Não 1D
ZxingJs Código aberto Não 1D e 2D (limitado)
CodeCorp Enterprise Sim 1D e 2D
Scandit Enterprise Sim 1D e 2D
Comparação de bibliotecas de leitura de código de barras comerciais e de código aberto

Todas as bibliotecas acima são SDKs completos que compõem todas as camadas discutidas acima. Elas também expõem interfaces para dar suporte a várias operações de verificação. Dependendo dos formatos de código de barras e da velocidade de detecção necessária para o caso de negócios, uma decisão pode ser entre soluções Wasm e não Wasm. Apesar do custo de exigir um recurso extra (Wasm) para decodificar o código de barras, as soluções Wasm são mais eficientes do que as que não usam o Wasm em termos de precisão.

A Scandit foi nossa principal escolha. Ele oferece suporte a todos os formatos de código de barras necessários para nossos casos de uso comercial. Ele supera todas as bibliotecas de código aberto disponíveis em velocidade de leitura.

O futuro da verificação

Quando a API Shape Detection tiver suporte total de todos os principais navegadores, poderemos ter um novo elemento HTML <scanner> com os recursos necessários para um leitor de código de barras. A equipe de engenharia da MishiPay acredita que há um caso de uso sólido para que a funcionalidade de leitura de código de barras seja um novo elemento HTML devido ao número crescente de bibliotecas licenciadas e de código aberto que estão permitindo experiências como o recurso "Scan & Go" e muitas outras.

Conclusão

A fadiga de apps é um problema que os desenvolvedores enfrentam quando os produtos entram no mercado. Muitas vezes, os usuários querem entender o valor que um aplicativo oferece antes de fazer o download. Em uma loja, em que o MishiPay economiza tempo dos compradores e melhora a experiência deles, é contra-intuitivo esperar por um download antes de usar um aplicativo. É aí que nossa PWA ajuda. Ao eliminar a barreira à entrada, aumentamos nossas transações em 10 vezes e permitimos que os usuários economizassem 2,5 anos de espera na fila.

Agradecimentos

Este artigo foi revisado por Joe Medley.