SDK da Web - Guia de implementação nativa em JavaScript

Documento

Visão geral

INFORMAÇÃO: A atribuição web é uma funcionalidade empresarial. Contacte o seu Gestor de Sucesso do Cliente para ativar esta funcionalidade na sua conta.

Este guia orienta a implementação do Singular WebSDK usando JavaScript nativo. Esse método oferece o rastreamento mais confiável e é recomendado para a maioria das implementações, pois não é bloqueado por bloqueadores de anúncios comuns.

IMPORTANTE!

  • Não implemente os métodos JavaScript nativo e Google Tag Manager. Escolha apenas um para evitar rastreamento duplicado.
  • O Singular WebSDK foi projetado para ser executado no lado do cliente, no navegador do usuário. Ele requer acesso a recursos do navegador, como localStorage e Document Object Model (DOM), para funcionar corretamente. Não tente executar o SDK no lado do servidor (por exemplo, via Next.js SSR ou node.js) — isso causará falhas no rastreamento, pois os ambientes de servidor não fornecem acesso às APIs do navegador.

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Chave SDK e Segredo SDK: 
  • ID do produto:
    • O que é: um nome exclusivo para o seu site, idealmente usando o formato DNS reverso (por exemplo, com.website-name).
    • Por que é importante: esse ID associa o site como um aplicativo no Singular e deve corresponder ao bundleID do aplicativo web listado na sua página de aplicativos no Singular. 
  • Permissão para editar o código HTML do seu site.
  • Acesso para adicionar JavaScript na seção <head> das suas páginas.
  • Uma lista de eventos que você deseja rastrear. Veja nossos Eventos Padrão do Singular: Lista Completa e Eventos Recomendados por Vertical para obter ideias.

Etapas de implementação


Etapa 1: Adicione o script da biblioteca SDK

Adicione o seguinte trecho de código à seção <head> de todas as páginas do seu site. Coloque-o o mais cedo possível, de preferência próximo ao topo da tag <head>.

DICA! Adicionar o script logo no início garante que a biblioteca JavaScript do Singular esteja disponível para qualquer função do Singular no código-fonte da sua página.

Latest VersionSpecific VersionUsing NPMNext.js / React
<script src="https://web-sdk-cdn.singular.net/singular-sdk/latest/singular-sdk.js"></script>

Etapa 2: Inicialize o SDK

  • Sempre inicialize o SDK cada vez que uma página for carregada no navegador.
  • A inicialização é necessária para todos os recursos de atribuição e rastreamento de eventos do Singular.
  • A inicialização aciona um __PAGE_VISIT__ evento.
  • O __PAGE_VISIT__ evento é usado para gerar uma nova sessão no lado do servidor quando as seguintes condições são atendidas:
    • O usuário chega com novos dados de publicidade na URL (como parâmetros UTM ou WP) ou
    • A sessão anterior expirou (após 30 minutos de inatividade).
    • As sessões são usadas para medir a retenção de usuários e apoiar a atribuição de reengajamento.
  1. Crie uma função de inicialização e chame essa função no DOM Ready após o carregamento da página.
  2. Certifique-se de que a inicialização ocorra antes que quaisquer outros eventos Singular sejam relatados.
  3. Para aplicativos de página única (SPA), inicialize o SDK Singular no primeiro carregamento da página e, em seguida, chame a função Singular Page Visist window.singularSdk.pageVisit() em cada mudança de rota que represente uma nova visualização de página.
Basic InitializationNext.js / React

Inicialização básica DOM-Ready

Adicione um ouvinte de eventos para chamar o initSingularSDK() em DOMContentLoaded

/**
 * Initializes the Singular SDK with the provided configuration.
 * @param {string} sdkKey - The SDK key for Singular.
 * @param {string} sdkSecret - The SDK secret for Singular.
 * @param {string} productId - The product ID for Singular.
 * @example
 * initSingularSDK(); // Initializes SDK with default config
 */
function initSingularSDK() {
  var config = new SingularConfig('sdkKey', 'sdkSecret', 'productId');
  window.singularSdk.init(config);
}

/**
 * Triggers Singular SDK initialization when the DOM is fully parsed.
 */
document.addEventListener('DOMContentLoaded', function() {
  initSingularSDK();
});

Inicialização básica com propriedades globais

Como o SDK Singular não está inicializado, você deve implementar a função personalizada para definir as propriedades globais no localstorage do navegador. Consulte a função personalizada setGlobalPropertyBeforeInit(). Depois de implementada, você pode definir as propriedades conforme descrito abaixo antes da inicialização do SDK.

/**
 * Initializes the Singular SDK with the provided configuration.
 * @param {string} sdkKey - The SDK key for Singular.
 * @param {string} sdkSecret - The SDK secret for Singular.
 * @param {string} productId - The product ID for Singular.
 * @example
 * initSingularSDK(); // Initializes SDK with default config
 */
function initSingularSDK() {
  var sdkKey = 'sdkKey';
  var sdkSecret = 'sdkSecret';
  var productId = 'productId';
  
  // Set global properties before SDK initialization
  setGlobalPropertyBeforeInit(sdkKey, productId, 'global_prop_1', 'test', false);
  setGlobalPropertyBeforeInit(sdkKey, productId, 'global_prop_2', 'US', true);
  
  // Initialize SDK
  var config = new SingularConfig('sdkKey', 'sdkSecret', 'productId');
  window.singularSdk.init(config);
}

/**
 * Triggers Singular SDK initialization when the DOM is fully parsed.
 */
document.addEventListener('DOMContentLoaded', function() {
  initSingularSDK();
});

Inicialização básica com roteamento de aplicativo de página única (SPA)

Cenário O que fazer

Primeiro carregamento da página

Chame window.singularSdk.init(config)

Navegando para uma nova rota/página

Chame window.singularSdk.pageVisit()

No carregamento inicial no SPA

Não chame window.singularSdk.pageVisit() (A inicialização fornecerá o evento da primeira visita à página.)

Exemplo para SPAs (React)

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

/**
 * Initializes the Singular SDK with the provided configuration.
 * @param {string} sdkKey - The SDK key for Singular.
 * @param {string} sdkSecret - The SDK secret for Singular.
 * @param {string} productId - The product ID for Singular.
 * @example
 * // Initialize the Singular SDK
 * initSingularSDK();
 */
function initSingularSDK() {
  var config = new SingularConfig('sdkKey', 'sdkSecret', 'productId');
  window.singularSdk.init(config);
}

/**
 * Tracks a page visit event with the Singular SDK on route changes.
 * @example
 * // Track a page visit
 * trackPageVisit();
 */
function trackPageVisit() {
  window.singularSdk.pageVisit();
}

/**
 * A React component that initializes the Singular SDK on mount and tracks page visits on route changes.
 * @returns {JSX.Element} The component rendering the SPA content.
 * @example
 * // Use in a React SPA with react-router-dom
 * function App() {
 *   const location = useLocation();
 *   useEffect(() => {
 *     initSingularSDK();
 *   }, []);
 *   useEffect(() => {
 *     trackPageVisit();
 *   }, [location.pathname]);
 *   return <div>Your SPA Content</div>;
 * }
 */
function App() {
  const location = useLocation();

  useEffect(() => {
    initSingularSDK();
  }, []); // Run once on mount for SDK initialization

  useEffect(() => {
    trackPageVisit();
  }, [location.pathname]); // Run on route changes for page visits

  return (
    <div>Your SPA Content</div>
  );
}

export default App;

Inicialização básica usando um callback de inicialização

Se você precisar executar o código após o SDK estar pronto (por exemplo, para obter o Singular Device ID), defina um callback com .withInitFinishedCallback():

/**
 * Initializes the Singular SDK with a callback to handle initialization completion.
 * @param {string} sdkKey - The SDK key for Singular.
 * @param {string} sdkSecret - The SDK secret for Singular.
 * @param {string} productId - The product ID for Singular.
 * @example
 * initSingularSDK(); // Initializes SDK and logs device ID
 */
function initSingularSDK() {
  var config = new SingularConfig('sdkKey', 'sdkSecret', 'productId')
    .withInitFinishedCallback(function(initParams) {
      var singularDeviceId = initParams.singularDeviceId;
      // Example: Store device ID for analytics
      console.log('Singular Device ID:', singularDeviceId);
      // Optionally store in localStorage or use for event tracking
      // localStorage.setItem('singularDeviceId', singularDeviceId);
    });

  window.singularSdk.init(config);
}

/**
 * Triggers Singular SDK initialization when the DOM is fully parsed.
 */
document.addEventListener('DOMContentLoaded', function() {
  initSingularSDK();
});
  • Substitua 'sdkKey' pela sua chave SDK real.
  • Substitua 'sdkSecret' pelo seu segredo SDK real.
  • Substitua 'productId' pelo seu ID do produto real. Deve ficar assim: com.website-name e deve corresponder ao valor BundleID na página Apps na plataforma Singular.

Opções de configuração

Aprimore a configuração do WebSDK encadeando métodos .with para habilitar recursos extras.

Por exemplo, para oferecer suporte ao rastreamento entre subdomínios, mantendo o Singular Device ID (SDID) em um cookie ou para incluir um ID de usuário personalizado para um visitante que retorna ao site com um estado de login ativo:

Config with Options
var domain = 'website-name.com';
var config = new SingularConfig('sdkKey','sdkSecret','productId')
  .withAutoPersistentSingularDeviceId(domain)
  .withCustomUserId(userId);

Referência do método SingularConfig

Aqui estão todos os métodos ".with" disponíveis.

Método Descrição Saiba mais
.withCustomUserId(customId) Enviar o ID do usuário para o Singular Definir o ID do usuário
.withProductName(productName) Um nome de exibição opcional para o produto  
.withLogLevel(logLevel) Configure o nível de registro: 0 - Nenhum (padrão); 1 - Aviso; 2 - Informação; 3 - Depuração.  
.withSessionTimeoutInMinutes(timeout) Defina o tempo limite da sessão em minutos (padrão: 30 minutos)

 

.withAutoPersistentSingularDeviceId(domain) Habilitar rastreamento automático entre subdomínios Persistência automática usando cookies

.withPersistentSingularDeviceId(singularDeviceId)

Ativar rastreamento manual entre subdomínios Definir manualmente o ID único do dispositivo
.withInitFinishedCallback(callback) Chamar um callback quando a inicialização do SDK estiver concluída Chamar uma função de retorno de chamada quando a inicialização estiver concluída
.withGlobalProperties(globalProperties, false) Definir propriedades globais durante a inicialização; o segundo parâmetro é overrideExisting (booleano). Use false para mesclar com as propriedades existentes, true para sobrescrever as propriedades existentes. Propriedades globais
.withEventsDedupEnabled() Habilite a deduplicação opcional de eventos para reduzir a exportação de eventos duplicados (por exemplo, gatilhos repetidos disparados em um curto intervalo) Deduplicação de eventos
.withTimeBetweenEvents(timeBetweenEvents) Defina a janela de tempo máxima (ms) para deduplicação (padrão: 1000 ms / 1 segundo) Deduplicação de eventos

Lista de verificação do desenvolvedor

  • Reúna suas credenciais SDK e ID do produto.
  • Decida se você precisa de configurações personalizadas (ID do usuário, tempo limite, etc.).
  • Crie uma função de inicialização Singular e um objeto SingularConfig usando os exemplos acima.
  • Sempre teste para garantir que a inicialização seja acionada apenas uma vez ao carregar a página.

DICA! Para configurações avançadas, como rastreamento de pesquisa orgânica , talvez seja necessário implementar JavaScript personalizado — por exemplo, para ajustar parâmetros de consulta — antes que o SDK Singular seja inicializado. Certifique-se de que seu código personalizado seja executado antes da função de inicialização Singular para que as alterações sejam capturadas corretamente. Mais detalhes sobre como implementar o rastreamento de pesquisa orgânica podem ser encontrados aqui.


Etapa 3: Rastreamento de eventos

Após inicializar o SDK, você pode rastrear eventos personalizados quando os usuários realizam ações importantes em seu site.

IMPORTANTE! O Singular não bloqueia eventos duplicados! É responsabilidade dos desenvolvedores adicionar proteções contra atualizações ou duplicações de página. Recomenda-se incorporar algum método de deduplicação específico para eventos de receita, a fim de evitar dados de receita errôneos. Veja "Etapa 5: Prevenção de eventos duplicados" abaixo para um exemplo.

Basic EventConversion EventRevenue Event

Rastreamento básico de eventos

Rastreie um evento simples ou adicione atributos personalizados usando JSON válido para fornecer mais contexto sobre o evento:

// Basic event tracking
var eventName = 'page_view';
window.singularSdk.event(eventName);
      
// Optional: With attributes for more context
var eventName = 'sng_content_view';
var attributes = {
  key1: 'value1', // First custom attribute
  key2: 'value2'  // Second custom attribute
};
window.singularSdk.event(eventName, attributes);

Padrões comuns de implementação de eventos

Page Load EventsButton Click EventsForm Submission Events

Eventos de carregamento de página

O mecanismo de rastreamento de eventos de carregamento de página usa JavaScript para monitorar quando uma página da web é totalmente carregada e, em seguida, aciona um evento de análise usando o SDK Singular. Especificamente, ele utiliza o método window.addEventListener('load', ...) para detectar quando todos os recursos da página (por exemplo, HTML, imagens, scripts) foram carregados. Após esse evento, a função event do SDK Singular é chamada para registrar um evento personalizado com atributos associados, permitindo o rastreamento das interações do usuário para fins de análise, como monitorar visualizações de página ou ações do usuário, como registros. O mecanismo é comumente usado em análises da web para capturar dados sobre o comportamento do usuário, como visitas à página ou ações específicas, com atributos personalizáveis para insights detalhados.

O mecanismo pode ser adaptado para rastrear um evento específico (por exemplo, um evento page_view ) com atributos personalizados, conforme mostrado abaixo. A estrutura do código permanece limpa e modular, com o nome do evento e os atributos definidos separadamente para maior clareza e facilidade de manutenção.

/**
 * Tracks a registration event with the Singular SDK when the page fully loads.
 * @param {string} eventName - The name of the event to track (e.g., 'page_view').
 * @param {Object} attributes - A JSON object with custom event attributes.
 * @param {string} attributes.key1 - First custom attribute (e.g., 'value1').
 * @param {string} attributes.key2 - Second custom attribute (e.g., 'value2').
 */
window.addEventListener('load', function() {
  var eventName = 'page_view';
  var attributes = {
    key1: 'value1', // First custom attribute
    key2: 'value2'  // Second custom attribute
  };
  window.singularSdk.event(eventName, attributes);
});

Etapa 4: Definir o ID do usuário do cliente

Você pode enviar sua ID de usuário interna para o Singular usando um método SDK do Singular.

NOTA: Se você usar a solução Cross-Device da Singular, deverá coletar a ID do usuário em todas as plataformas.

  • A ID do usuário pode ser qualquer identificador e não deve expor PII (informações de identificação pessoal). Por exemplo, você não deve usar o endereço de e-mail, nome de usuário ou número de telefone de um usuário. A Singular recomenda o uso de um valor hash exclusivo apenas para seus dados primários .
  • O valor do ID do usuário passado para o Singular também deve ser o mesmo ID interno do usuário que você captura em todas as plataformas (Web/Mobile/PC/Console/Offline).
  • A Singular incluirá a ID do usuário em exportações no nível do usuário, ETL e postbacks internos de BI (se configurados). A ID do usuário é um dado primário, e a Singular não a compartilha com terceiros.
  • O valor do ID do usuário, quando definido com o método Singular SDK, permanecerá até ser desativado usando o método logout() ou até que o armazenamento local do navegador seja excluído. Fechar ou atualizar o site não desativa o ID do usuário.
  • No modo privado/incógnito, o SDK não pode manter a ID do usuário porque o navegador exclui automaticamente o armazenamento local quando é fechado.

Para definir a ID do usuário, use o método login(). Para desativá-la (por exemplo, se o usuário "sair" da conta), chame o método logout() .

NOTA: Se vários usuários usarem um único dispositivo, recomendamos implementar um fluxo de logout para definir e desativar o ID do usuário para cada login e logout.

Se você já souber o ID do usuário quando o SDK Singular for inicializado no site, defina o ID do usuário no objeto de configuração. Dessa forma, o Singular pode ter o ID do usuário desde a primeira sessão. No entanto, o ID do usuário normalmente não está disponível até o O usuário se registra ou faz login. Nesse caso, chame login() após a conclusão do fluxo de registro.

DICA! Use o mesmo ID de usuário do cliente que você usa em seus SDKs móveis. Isso permite a atribuição entre dispositivos e fornece uma visão completa do comportamento do usuário em todas as plataformas.

Práticas recomendadas para a ID de usuário do cliente:

  • Defina-a assim que o usuário fizer login ou se cadastrar
  • Use a mesma ID nas plataformas web e móveis
  • Não use informações de identificação pessoal (e-mail, número de telefone)
  • Use sua ID de usuário interna ou ID de banco de dados
  • Envie como uma string, mesmo que seja numérica:
Set the User IDUnset the User ID
// After user logs in or signs up
var userId = 'user_12345';
window.singularSdk.login(userId);

Etapa 5: Desduplicação de eventos (opcional)

IMPORTANTE! Se o seu site puder disparar o mesmo gatilho mais de uma vez em um curto intervalo de tempo, você poderá ver eventos duplicados exportados. Habilite a deduplicação do SDK para suprimir automaticamente as duplicatas.

O SDK da Web da Singular oferece suporte à deduplicação opcional de eventos para reduzir exportações duplicadas causadas por gatilhos repetidos disparados em um curto intervalo de tempo. Quando ativado, o SDK descartará eventos duplicados que correspondam aos mesmos parâmetros de deduplicação dentro do intervalo de tempo configurado.

Como ativar

  • withEventsDedupEnabled: Ative a deduplicação de eventos (o padrão é desativado).
  • withTimeBetweenEvents: Janela de tempo máxima (em milissegundos) usada para considerar dois eventos duplicados; o padrão é 1000 ms (1 segundo).
JavaScript

JavaScript

// Enable optional event deduplication (recommended when triggers may fire repeatedly)
var config = new SingularConfig("SDK_KEY", "SDK_SECRET", "PRODUCT_ID")
  .withEventsDedupEnabled()     // turns deduplication on
  .withTimeBetweenEvents(1000); // dedup window in ms (default: 1000 = 1s)

window.singularSdk.init(config);

Como as duplicatas são detectadas

Quando a deduplicação está ativada, o SDK calcula um hash a partir dos campos-chave do evento e suprime repetições dentro da janela de tempo. Os parâmetros de deduplicação incluem: EventName, EventProductName, IsRevenueEvent, CustomUserId, GlobalProperties, MatchId e WebUrl (e o SDK também leva em consideração cargas "extras" adicionais do evento, como receita/args, ao fazer o hash).


Etapa 6: Testando sua implementação

Após implementar o SDK, verifique se ele está funcionando corretamente usando as ferramentas de desenvolvedor do seu navegador.

Verifique se o SDK foi carregado

  1. Abra seu site em um navegador
  2. Abra as Ferramentas de desenvolvedor (F12 ou clique com o botão direito → Inspecionar)
  3. Vá para a guia Console
  4. Digite typeof singularSdk e pressione Enter
  5. Você deverá ver um objeto "função", não "indefinido"

Verifique as solicitações de rede

  1. Abra as Ferramentas do desenvolvedor (F12)
  2. Vá para a guia Rede
  3. Recarregue a página
  4. Filtre por singular ou sdk-api
  5. Procure por solicitações para sdk-api-v1.singular.net
  6. Clique em uma solicitação para ver os detalhes
  7. Verifique se o código de status é 200
  8. Verifique se a carga útil da solicitação contém o ID do seu produto. Ele estará no parâmetro "i" da carga útil.

SUCESSO! Se você vir solicitações para sdk-api-v1.singular.net com o código de status 200, seu SDK está enviando dados para o Singular com sucesso.

Verifique os eventos

  1. Acione um evento no seu site (clique em um botão, envie um formulário etc.).
  2. Na guia Rede, procure uma nova solicitação para sdk-api-v1.singular.net
  3. Clique na solicitação e visualize a guia Carga útil ou Solicitação
  4. Verifique se o nome do seu evento "n" aparece na solicitação

    event_test.png

Para testes de ponta a ponta, use o Console de Testes

Você pode testar a integração do Web SDK usando o Console SDK disponível no painel do Singular.

  1. Na plataforma Singular, vá para Ferramentas do desenvolvedor > Console de testes.
  2. Clique em Adicionar dispositivo.
  3. Selecione a plataforma "Web" e insira o ID do dispositivo Singular.
  4. Obtenha o ID do dispositivo Singular na carga útil do navegador. Verifique a captura de tela acima para localizar o ID do dispositivo Singular ( SDID ) em um evento.
  5. O console de teste deve permanecer ativo enquanto você testa em uma janela separada. O console não exibirá nenhum evento acionado enquanto estiver fechado ou offline.
  6. Depois que o SDID for adicionado, você poderá recarregar a página da web e acionar alguns eventos. O "__PAGE_VISIT__" e outros eventos (se acionados) serão exibidos no Console SDK.
  7. Utilizar os logs de exportação (Reports & Insights Export Logs) é outra maneira de verificar os resultados dos testes. Esse conjunto de dados tem um atraso de 1 hora.

Etapa 7: implementar o encaminhamento da Web para o aplicativo

Encaminhamento de atribuição Web-to-App

Use o Singular WebSDK para rastrear as jornadas dos usuários do seu site para o seu aplicativo móvel, permitindo a atribuição precisa da campanha da web às instalações e reengajamentos do aplicativo móvel. Siga estas etapas para configurar o encaminhamento da web para o aplicativo, incluindo suporte a código QR para usuários de desktop.

  1. Siga nosso Guia de encaminhamento de atribuição do site para o aplicativo móvel para configurar o Singular WebSDK para atribuição da web móvel.
  2. Para rastreamento de desktop para aplicativo:
    • Conclua a configuração no guia acima.
    • Use o link do Singular Mobile Web-to-App (por exemplo, https://yourlink.sng.link/...) e a função WebSDK buildWebToAppLink(link) com uma biblioteca de códigos QR dinâmicos como QRCode.js.
    • Gere um código QR na sua página da Web que codifique o link. Os usuários de desktop podem digitalizá-lo com seus dispositivos móveis para abrir o aplicativo, passando os dados da campanha para atribuição.
    • Explore nossa demonstração do Singular WebSDK para ver um exemplo prático de geração de código QR e gerenciamento de links web-to-app.

DICA! As visualizações da web no navegador do aplicativo móvel (como as usadas pelo Facebook, Instagram e TikTok) podem fazer com que o ID do dispositivo Singular mude se o usuário mudar para o navegador nativo do dispositivo, interrompendo a atribuição.

Para evitar isso, sempre use o formato de link de rastreamento Singular adequado para cada rede de anúncios:


Demonstração do Singular WebSDK

Abaixo está uma implementação simples, mas abrangente, usando a API Singular WebSDK documentada. Esta amostra fornece uma separação clara para eventos personalizados, eventos de conversão, eventos de receita e suporte a links da web para aplicativos usando o encaminhamento da web para aplicativos suportado pelo WebSDK.

Você pode executar este código em um arquivo HTML local ou modificá-lo em seu site para integração avançada e solução de problemas.

Demonstração do Singular WebSDK (código-fonte)
#

Copie e cole o código abaixo como um arquivo HTML e abra-o no seu navegador.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <title>Singular WebSDK Demo</title>
  <script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
  <script src="https://web-sdk-cdn.singular.net/singular-sdk/latest/singular-sdk.js"></script>

  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif;
      line-height: 1.6;
      color: #1a1d29;
      background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
      padding: 40px 20px;
      min-height: 100vh;
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
      background: white;
      padding: 48px;
      border-radius: 16px;
      box-shadow: 0 4px 24px rgba(30, 41, 59, 0.08);
      border: 1px solid rgba(148, 163, 184, 0.1);
    }

    .header-brand {
      display: flex;
      align-items: center;
      margin-bottom: 32px;
      padding-bottom: 24px;
      border-bottom: 2px solid #f1f5f9;
    }

    .brand-dot {
      width: 12px;
      height: 12px;
      background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
      border-radius: 50%;
      margin-right: 12px;
    }

    h1 {
      font-size: 32px;
      font-weight: 700;
      color: #0f172a;
      letter-spacing: -0.025em;
    }

    h2 {
      font-size: 24px;
      font-weight: 600;
      margin: 48px 0 24px 0;
      color: #1e293b;
      padding-bottom: 12px;
      border-bottom: 2px solid #e2e8f0;
      position: relative;
    }

    h2:before {
      content: '';
      position: absolute;
      bottom: -2px;
      left: 0;
      width: 60px;
      height: 2px;
      background: linear-gradient(90deg, #6366f1, #8b5cf6);
    }

    p {
      margin-bottom: 18px;
      color: #475569;
      font-size: 15px;
    }

    strong {
      color: #1e293b;
      font-weight: 600;
    }

    .form-group {
      margin-bottom: 24px;
    }

    .radio-group {
      display: flex;
      gap: 24px;
      margin-bottom: 24px;
      padding: 16px;
      background: #f8fafc;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
    }

    .radio-group label {
      display: flex;
      align-items: center;
      gap: 10px;
      cursor: pointer;
      font-size: 14px;
      font-weight: 500;
      color: #475569;
      transition: color 0.2s ease;
    }

    .radio-group label:hover {
      color: #1e293b;
    }

    input[type="radio"] {
      width: 20px;
      height: 20px;
      cursor: pointer;
      accent-color: #6366f1;
    }

    input[type="text"] {
      width: 100%;
      padding: 14px 18px;
      font-size: 15px;
      font-weight: 400;
      border: 2px solid #e2e8f0;
      border-radius: 12px;
      transition: all 0.2s ease;
      background: #fafbfc;
      color: #1e293b;
    }

    input[type="text"]:focus {
      outline: none;
      border-color: #6366f1;
      background: white;
      box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
    }

    input[type="text"]::placeholder {
      color: #94a3b8;
      font-weight: 400;
    }

    button {
      padding: 14px 32px;
      font-size: 15px;
      font-weight: 700;
      color: #fff;
      background: linear-gradient(90deg, #2363f6 0%, #1672fe 100%);
      border: none;
      border-radius: 4px;  /* Pill shape */
      cursor: pointer;
      box-shadow: 0 2px 8px rgba(35, 99, 246, 0.12);
      transition: background 0.2s, transform 0.2s;
      letter-spacing: 0.03em;
    }
    button:hover {
      background: linear-gradient(90deg, #1672fe 0%, #2363f6 100%);
      transform: translateY(-2px);
      box-shadow: 0 8px 24px rgba(22, 114, 254, 0.18);
    }
    button:active {
      transform: translateY(0);
    }

    a {
      color: #6366f1;
      text-decoration: none;
      font-weight: 600;
      transition: all 0.2s ease;
      position: relative;
    }

    a:hover {
      color: #4f46e5;
    }

    a:after {
      content: '';
      position: absolute;
      width: 0;
      height: 2px;
      bottom: -2px;
      left: 0;
      background: #6366f1;
      transition: width 0.2s ease;
    }

    a:hover:after {
      width: 100%;
    }

    ol {
      margin-left: 10px;
      margin-bottom: 18px;
    }

    ol li {
      margin-left: 10px;
    }

    .info-box {
      background: linear-gradient(135deg, #eff6ff 0%, #f0f9ff 100%);
      border-left: 4px solid #6366f1;
      padding: 20px;
      margin: 24px 0;
      border-radius: 12px;
      border: 1px solid rgba(99, 102, 241, 0.1);
    }

    .info-box p {
      color: #1e40af;
      margin-bottom: 0;
    }

    .section-label {
      font-size: 12px;
      font-weight: 700;
      color: #6b7280;
      margin-bottom: 10px;
      text-transform: uppercase;
      letter-spacing: 1px;
    }

    .button-group {
      display: flex;
      align-items: center;
      gap: 16px;
      flex-wrap: wrap;
    }

    .analytics-badge {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
      color: white;
      padding: 6px 12px;
      border-radius: 20px;
      font-size: 12px;
      font-weight: 600;
      margin-bottom: 16px;
    }

    .feature-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 16px;
      margin: 24px 0;
    }

    .feature-item {
      padding: 16px;
      background: #f8fafc;
      border-radius: 10px;
      border: 1px solid #e2e8f0;
      text-align: center;
    }

    .feature-item strong {
      display: block;
      color: #6366f1;
      font-size: 14px;
      margin-bottom: 4px;
    }

    .metric-dot {
      width: 8px;
      height: 8px;
      background: #10b981;
      border-radius: 50%;
      display: inline-block;
      margin-right: 8px;
      animation: pulse 2s infinite;
    }

    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.5; }
    }
  </style>

</head>

<body>
  <div class="container">
    <div class="header-brand">
      <div class="brand-dot"></div>
      <h1>Singular WebSDK Demo</h1>
    </div>

    <p>
      Below is a simple but comprehensive implementation using the documented Singular WebSDK API. 
      This sample provides clear separation for <strong>custom events</strong>, <strong>conversion events</strong>, <strong>revenue events</strong>, and <strong>web-to-app link support using WebSDK supported Web-to-App forwarding</strong>. </p>
      <p>You can run this code in a local HTML file or modify it in your site for advanced integration and troubleshooting.
    </p>

    <h2>SDK Initialization Testing</h2>
    <ol>
      <li>Open your browsers developer tools.</li>
      <li>Inspect the Network tab and filter for "sdk-api-v1.singular.net"</li>
      <li>Refresh this page, and examin the payload of the request.</li>
    </ol>


    <hr>

    <h2>User Authentication</h2>
    <p>User authentication is key to supporting cross-device attribution. Pass the common User ID value that would also be sent to Singular from mobile SDKs for cross-device continuity.</p>
    <div class="form-group">
      <div class="section-label">Simulate User Authentication</div>
      <input type="text" id="userId" placeholder="Enter a User ID"/>
    </div>
    <div class="form-group">
      <div class="button-group">
        <button onclick="setUserId()">Set the User ID (Login)</button>
        <button onclick="unsetUserId()">Unset the User ID (Logout)</button>
      </div>
    </div>

    <hr>

    <h2>SDK Event Testing</h2>
    <div class="form-group">
      <div class="section-label">Event Type Selection</div>
      <div class="radio-group">
        <label>
          <input type="radio" name="eventType" value="custom" checked onchange="handleRevenueFields(this)">
          <span>Custom Event</span>
        </label>
        <label>
          <input type="radio" name="eventType" value="conversion" onchange="handleRevenueFields(this)">
          <span>Conversion Event</span>
        </label>
        <label>
          <input type="radio" name="eventType" value="revenue" onchange="handleRevenueFields(this)">
          <span>Revenue Event</span>
        </label>
      </div>
    </div>

    <div class="form-group">
      <div class="section-label">Event Configuration</div>
      <input type="text" id="eventName" placeholder="Enter event name"/>
    </div>

    <div class="form-group" id="currencyGroup" style="display:none">
      <input type="text" id="currency" placeholder="Currency code (e.g., USD, EUR)"/>
    </div>

    <div class="form-group" id="amountGroup" style="display:none">
      <input type="text" id="amount" placeholder="Revenue amount (e.g., 29.99)"/>
    </div>

    <div class="form-group" id="attributesGroup" style="display:none">
      <input type="text" id="attributes" placeholder='Optional attributes (JSON, e.g. {"color":"blue"})'/>
    </div>

    <div class="form-group">
      <button id="send" onclick="sendCustomEvent()">Send Event to Singular</button>
    </div>

    <hr>
    <h2>Web-to-App Forwarding</h2>
    <div class="form-group">
    <ol>
      <li><a href="https://support.singular.net/hc/pt-br/articles/360042283811" target="_blank">Learn more about Web-to-App Forwarding</a></li>
    <li>In the page source code you will find the mobile web-to-app base link "<strong>https://seteam.sng.link/D0mvs/y3br?_smtype=3</strong>" used for demonstration purposes.</li>
    <li>Replace all occurances of the link with your own Singular Mobile Web-to-App link to test functionality.</li>
    <li>Add Singular Web Parameters to the URL and refresh the page. (example: "<strong>?wpsrc=SingularTest&wpcn=MyCampaign</strong>").</li>
  </ol>

    <hr>
    <div class="section-label">Mobile Web-to-App Test</div>
    <div class="form-group">
      <div class="button-group">
        <button onclick="displayWebLink()">Display Constructed Web-to-App Link</button>
        <button onclick="testWebLink()">Test Web-to-App Link</button>
      </div>
    </div>
  </div>
    <hr>
    <div class="section-label">Desktop Web-to-App Configuration</div>
    <div class="form-group">
    <p>Use a dynamic QR Code generation library like <a href="https://davidshimjs.github.io/qrcodejs/" target="_blank">QRCode.js</a> to build and display a QR code using the Singular Mobile Web-to-App link with constructed campaign parameters.</p>
    <div id="qrcode"></div>
    </div>

  </div>
  
  <script>
    /**
     * Initializes the Singular SDK with the provided configuration.
     * @param {string} sdkKey - The SDK key for Singular (e.g., 'se_team_9b3431b0').
     * @param {string} sdkSecret - The SDK secret for Singular (e.g., 'bcdee06e8490949422c071437da5c5ed').
     * @param {string} productId - The product ID for Singular (e.g., 'com.website').
     * @example
     * // Initialize the Singular SDK
     * initSingularSDK('se_team_9b3431b0', 'bcdee06e8490949422c071437da5c5ed', 'com.website');
     */
    function initSingularSDK() {
      var sdkKey = 'se_team_9b3431b0';
      var sdkSecret = 'bcdee06e8490949422c071437da5c5ed';
      var productId = 'com.website';

      // Global Properties set during init (plain object; max 5 keys persisted).
      const globalProperties = {
        plan: "pro",
        region: "us"
      };

      // Applies to the whole object: false = merge with existing, true = clear existing then set.
      const overrideExistingGlobalProperties = false; // required

      const config = new SingularConfig(sdkKey, sdkSecret, productId)
        .withLogLevel(3)
        .withSessionTimeoutInMinutes(0.5)
        .withGlobalProperties(globalProperties, overrideExistingGlobalProperties)
        .withInitFinishedCallback(function (initParams) {
          console.log("Singular Device ID:", initParams.singularDeviceId);
          console.log("Global props (SDK):", window.singularSdk.getGlobalProperties());

          // If you need to override just one key after init set it in the withInitFinishedCallback:
          window.singularSdk.setGlobalProperties("plan", "enterprise");
    });

      // Initialize the Singular SDK
      window.singularSdk.init(config);
      generateDesktopWebToAppQRCode(); // Generate QR code after initialization
    }

    /**
     * Triggers Singular SDK initialization when the DOM is fully parsed.
     * @example
     * document.addEventListener('DOMContentLoaded', function() {
     *   initSingularSDK();
     * });
     */
    document.addEventListener('DOMContentLoaded', function() {
      initSingularSDK();
    });


    // Fires a custom event using the Singular SDK
    function sendCustomEvent() {
      var eventName = document.getElementById('eventName').value;
      window.singularSdk.event(eventName);
    }

    // Fires a conversion event using the Singular SDK
    function sendConversionEvent() {
      var eventName = document.getElementById('eventName').value;
      window.singularSdk.conversionEvent(eventName);
    }

    // Fires a revenue event only once per session with deduplication
    // Parameters:
    //   - eventName: string (name of event), default "web_purchase" if blank
    //   - amount: revenue amount, default 0 if blank
    //   - currency: string, defaults to "USD" if blank
    //   - attributes: optional object with extra payload
    function sendRevenueEvent(eventName, amount, currency, attributes) {
      // Fill in defaults and normalize values
      eventName = eventName ? eventName : "web_purchase";
      currency = currency ? currency.toUpperCase() : "USD";
      amount = amount ? amount : 0;

      // Create a unique key based on event data for deduplication
      // btoa(JSON.stringify(...)) ensures order consistency in local/sessionStorage
      var payload = {
        eventName: eventName,
        amount: amount,
        currency: currency,
        attributes: attributes ? attributes : null
      };
      var storageKey = 'singular_revenue_' + btoa(JSON.stringify(payload));

      // Only fire event if no identical event has already fired in this tab/session
      if (!sessionStorage.getItem(storageKey)) {
        sessionStorage.setItem(storageKey, 'true');
        if (attributes && typeof attributes === 'object' && Object.keys(attributes).length > 0) {
          // Fire event with attributes payload
          window.singularSdk.revenue(eventName, currency, amount, attributes);
        } else {
          // Fire simple revenue event
          window.singularSdk.revenue(eventName, currency, amount);
        }
        console.log("Revenue event sent:", payload);
      } else {
        // Duplicate detected, don't send to SDK
        console.log("Duplicate revenue event prevented:", payload);
        alert("Duplicate revenue event prevented!");
      }
    }

    // Collects form values, validates attributes JSON, and calls sendRevenueEvent()
    // Ensures only valid values are sent and blocks on malformed JSON
    function fireFormRevenueEvent() {
      var eventName = document.getElementById('eventName').value;
      var currency = document.getElementById('currency').value;
      var amount = document.getElementById('amount').value;
      
      var attributesRaw = document.getElementById('attributes').value;
      var attributes = null;
      if (attributesRaw) {
        try {
          // Try to parse the optional attributes field from JSON string
          attributes = JSON.parse(attributesRaw);
        } catch (e) {
          alert("Optional attributes must be valid JSON.");
          return; // Stop if invalid JSON
        }
      }

      // Calls main revenue logic for deduplication and event sending
      sendRevenueEvent(eventName, amount, currency, attributes);
    }

    // Controls which form fields are visible depending on selected event type
    // Revenue events require currency, amount, and attributes fields
    function handleRevenueFields(sender) {
      var isRevenue = sender.value === "revenue";
      document.getElementById("currencyGroup").style.display = isRevenue ? "block" : "none";
      document.getElementById("amountGroup").style.display = isRevenue ? "block" : "none";
      document.getElementById("attributesGroup").style.display = isRevenue ? "block" : "none";

      // Dynamically assign the event button's onclick handler
      var send = document.getElementById("send");
      send.onclick = (sender.value === "custom") ? sendCustomEvent
        : (sender.value === "conversion") ? sendConversionEvent
        : fireFormRevenueEvent; // Only fires revenue logic for "revenue"
    }

    // Opens demo Singular web-to-app link in a new tab/window
    function testWebLink() {
      var singularWebToAppBaseLink = 'https://seteam.sng.link/D0mvs/y3br?_smtype=3';
      window.open(singularWebToAppBaseLink);
    }

    // Displays constructed Singular web-to-app link with campaign parameters
    function displayWebLink() {
      var singularWebToAppBaseLink = 'https://seteam.sng.link/D0mvs/y3br?_smtype=3';
      var builtLink = window.singularSdk.buildWebToAppLink(singularWebToAppBaseLink);
      console.log("Singular Web-to-App Link: ", builtLink);
      alert("Singular Web-to-App Link: " + builtLink);
    }

    // Generates QR code for desktop deep linking using Singular Mobile Web-to-App link
    function generateDesktopWebToAppQRCode() {
      var singularWebToAppBaseLink = 'https://seteam.sng.link/D0mvs/y3br?_smtype=3';
      const value = window.singularSdk.buildWebToAppLink(singularWebToAppBaseLink);
      new QRCode(document.getElementById("qrcode"), {
        text: value,
        width: 128,
        height: 128,
        colorDark: "#000",
        colorLight: "#fff",
        correctLevel: QRCode.CorrectLevel.H
      });
    }

    // Simulate user authentication and send login event
    function setUserId() {
      var userId = document.getElementById('userId').value;
      window.singularSdk.login(userId);
      console.log("Singular User ID is Set to: " + userId);
      window.singularSdk.event("sng_login");
    }

    // Simulate user logout and unset Singular user ID
    function unsetUserId() {
      window.singularSdk.logout();
      console.log("Singular User ID is Unset");
    }
  </script>
</body>
</html>

Tópicos avançados

Banners Singular

Habilitar banners Singular
#

INFORMAÇÃO: Banners singulares é um recurso empresarial . Para saber mais sobre esse recurso, entre em contato com seu Gerente de Sucesso do Cliente.

Os banners singulares podem ser exibidos em seu site móvel para direcionar os usuários da web de forma integrada ao seu aplicativo e exibir o conteúdo mais relevante do aplicativo. Depois de ativar os banners singulares em seu site, sua organização poderá facilmente criar, implantar e manter banners por meio da interface do usuário dos banners singulares.

Artigos relacionados

Guia de implementação passo a passo

  1. Adicione o script Singular Native JavaScript WebSDK ao seu site.

    Siga o guia de integração acima para adicionar o JavaScript WebSDK nativo Singular ao seu site antes de prosseguir com a implementação dos banners.

  2. Conceda permissão ao Singular para acessar dados de dicas do cliente

    Com as limitações nos dados do agente do usuário em navegadores baseados em Chromium , implementadas em fevereiro-março de 2023, os anunciantes agora precisam obter dados de dicas do cliente, bem como conceder ao Singular WebSDK permissão para receber esses dados. Para mais informações, consulte as Perguntas frequentes sobre banners.

    O site precisa:

    • Começar a solicitar dicas do cliente (accept-ch header).
    • Conceder permissão ao Singular (como terceiro) para que o navegador envie ao Singular as dicas do cliente nas solicitações de banner (permissions-policy header).

    Adicionar os seguintes cabeçalhos de resposta à resposta de carregamento da página:

    accept-ch:
    sec-ch-ua-model,
    sec-ch-ua-platform-version,
    sec-ch-ua-full-version-list
    
    permissions-policy:
    ch-ua-model=("https://sdk-api-v1.singular.net"),
    ch-ua-platform-version=("https://sdk-api-v1.singular.net"),
    ch-ua-full-version-list=("https://sdk-api-v1.singular.net")
  3. Adicionar a opção de configuração de banner à inicialização do WebSDK

    Os banners Singular exibem prompts inteligentes de download de aplicativos em seu site móvel, preservando a atribuição da fonte de marketing original. Quando habilitado com suporte web-to-app, o SDK rastreia qual rede de anúncios ou campanha trouxe o usuário ao seu site e, em seguida, atribui a instalação subsequente do aplicativo de volta à fonte original.

    /**
     * Initialize Singular SDK with Banner support and web-to-app attribution.
     * This enables smart banners that direct mobile web users to download your app
     * while preserving the original marketing source (UTM parameters, ad network, etc.)
     * for proper attribution when the app is installed.
     * @param {string} sdkKey - Your Singular SDK Key
     * @param {string} sdkSecret - Your Singular SDK Secret
     * @param {string} productId - Your Product ID (e.g., com.your-website)
     */
    function initSingularSDK() {
      // Enable web-to-app tracking to preserve attribution data
      var bannersOptions = new BannersOptions().withWebToAppSupport();
      
      // Configure SDK with banner support
      var config = new SingularConfig(sdkKey, sdkSecret, productId)
        .withBannersSupport(bannersOptions);
      
      // Initialize the SDK
      window.singularSdk.init(config);
      
      // Display the smart banner
      window.singularSdk.showBanner();
    }
    
    // Call on DOM ready
    document.addEventListener('DOMContentLoaded', function() {
      initSingularSDK();
    });
  4. Exibir novamente o banner na rota da página (apenas aplicativos de página única)

    Se o seu aplicativo for um aplicativo de página única, você terá que ocultar e exibir novamente o banner em cada rota de página. Isso garante que o Singular entregue o banner apropriado para a sua experiência na web.

    Para ocultar e exibir novamente o banner, use o seguinte código:

    window.singularSdk.hideBanner();
    window.singularSdk.showBanner();
  5. [Opção avançada] Personalizar configurações de link

    O Singular oferece uma maneira de personalizar os links no banner por meio de código.

    Para personalizar links:

    • Crie um objeto LinkParams e use uma ou mais das funções abaixo. Faça isso antes de chamar window.singularSdk.showBanner() .
    • Em seguida, passe o objeto LinkParams quando você chamar window.singularSdk.showBanner().

    Exemplo:

    // Define a LinkParams object
    let bannerParams = new LinkParams();
    
    // Configure link options (see details on each option below)
    bannerParams.withAndroidRedirect("androidRedirectValue");
    bannerParams.withAndroidDL("androidDLParamValue");
    bannerParams.withAndroidDDL("androidDDLparamValue");
    bannerParams.withIosRedirect("iosRedirectValue");
    bannerParams.withIosDL("iosDLValue");
    bannerParams.withIosDDL("iosDDLValue");
    
    // Show the banner with the defined options
    window.singularSdk.showBanner(bannerParams);

    Lista de opções:

    Método Descrição
    withAndroidRedirect Passe um link de redirecionamento para a página de download do seu aplicativo Android , geralmente uma página da Play Store.
    withAndroidDL Passe um link direto para uma página dentro do seu aplicativo Android.
    withAndroidDDL Passe um link direto diferido, ou seja, um link para uma página no seu aplicativo Android que o usuário ainda não instalou .
    withIosRedirect Passe um link de redirecionamento para a página de download do seu aplicativo iOS , geralmente uma página da App Store.
    withIosDL Passe um link direto para uma página dentro do seu aplicativo iOS.
    withIosDDL Passe um link direto diferido, ou seja, um link para uma página no seu aplicativo iOS que o usuário ainda não instalou .
  6. [Opção avançada] Use código para forçar a ocultação/exibição de banners

    Conforme mencionado na etapa 3, se você tiver um aplicativo de página única, deve usar os métodos hideBanner() e showBanner() em cada rota de página para garantir que o banner apropriado seja exibido (veja acima).

    hideBanner() e showBanner() também estão disponíveis para você usar em todo o seu código se quiser ocultar um banner que seria exibido ou exibir novamente um banner que você ocultou.

    Método Descrição
    singularSdk.hideBanner() Ocultar um banner visível da sua página.
    singularSdk.showBanner() Mostra o banner pré-configurado.
    singularSdk.showBanner(params) Mostrar o banner pré-configurado, mas substituir links pelas opções definidas no objeto linkParams ( veja a etapa 4).

Propriedades globais

Propriedades globais
#

O SDK Singular permite definir propriedades personalizadas a serem enviadas aos servidores Singular junto com cada sessão e evento enviado pelo aplicativo. Essas propriedades podem representar qualquer informação que você desejar sobre o usuário, o modo/status do aplicativo ou qualquer outra coisa.

  • Você pode definir até 5 propriedades globais como um objeto JSON válido. As propriedades globais são mantidas nos navegadores localstorage até serem apagadas ou o contexto do navegador ser alterado.

  • Cada nome e valor de propriedade pode ter até 200 caracteres. Se você passar um nome ou valor de propriedade mais longo, ele será truncado para 200 caracteres.

  • As propriedades globais são atualmente refletidas nos logs de eventos no nível do usuário do Singular (consulte Exportando logs de atribuição) e nos postbacks.

  • As propriedades globais estão disponíveis para mim enviadas em postbacks do Singular para terceiros para fins de correspondência, se necessário.

Para oferecer suporte à configuração de propriedades globais durante a inicialização do WebSDK, você deve implementar a opção .withGlobalProperties() no objeto de configuração.

Para lidar com propriedades globais após a inicialização, você deve usar as funções SDK: setGlobalProperties(), getGlobalProperties() , clearGlobalProperties() .

.withGlobalProperties()setGlobalProperties()getGlobalProperties()clearGlobalProperties()
/**
 * Set a Singular global property during SDK initialization.
 * Allows up to 5 key/value pairs. Optionally overwrites existing value for a key.
 * @param {{[key: string]: string}} globalProperties - The global property key/value pair object.
 * @param {string} propertyKey - The property key to set.
 * @param {string} propertyValue - The property value to set.
 * @param {boolean} overrideExisting - Whether to overwrite the property if it already exists.
 */
            
 // Global Properties set during init (plain object; max 5 keys persisted).
 var globalProperties = {
   propertyKey: propertyValue
 };

 // Set the override, applies to the whole object: false = merge with existing, true = clear existing then set.
 var overrideExisting = false; // required

 var config = new SingularConfig(sdkKey, sdkSecret, productId)
   .withLogLevel(3)
   .withSessionTimeoutInMinutes(0.5)
   .withGlobalProperties(globalProperties, overrideExisting)
   .withInitFinishedCallback(function (initParams) {
      console.log("Singular Device ID:", initParams.singularDeviceId);
      console.log("Global props (SDK):", window.singularSdk.getGlobalProperties());

      // If you need to override just one key after init set it in the withInitFinishedCallback:
      window.singularSdk.setGlobalProperties("plan", "enterprise");
  });

  // Initialize the Singular SDK
  window.singularSdk.init(config);           

Rastreamento de pesquisa orgânica

Exemplo de rastreamento de pesquisa orgânica
#

IMPORTANTE! Este exemplo é fornecido como uma solução alternativa para ativar o rastreamento de pesquisa orgânica. O código deve ser usado apenas como exemplo e atualizado e mantido pelo desenvolvedor web com base nas necessidades do seu departamento de marketing. O rastreamento de pesquisa orgânica pode ter significados diferentes para cada anunciante. Por favor, revisar a amostra e ajustar de acordo com suas necessidades.

Por que usar isso?

  • Garante que as visitas de pesquisa orgânica sejam rastreadas corretamente, mesmo que não haja parâmetros de campanha.

  • Anexa o parâmetro singular "Fonte" wpsrc com o valor do (referenciador) e o parâmetro "Nome da campanha" wpcn como "OrganicSearch" à URL para uma atribuição clara .

  • Armazena a URL atual e o referenciador em localStorage para uso posterior.

  • JavaScript puro, sem dependências e fácil de integrar.

Como funciona

  1. Verifica a URL da página em busca de parâmetros de campanha conhecidos de (Google, Facebook, TikTok, UTMs, etc.).

  2. Se não houver parâmetros de campanha e o referenciador for um mecanismo de pesquisa, acrescenta:

    • wpsrc (com o referenciador como seu valor)
    • wpcn (com OrganicSearch como seu valor)
  3. Atualiza a URL no navegador sem recarregar a página.

  4. Armazena o URL atual e o referenciador em localStorage como sng_url e sng_ref.

Utilização

  1. Adicione setupOrganicSearchTracking.js ao seu site como uma biblioteca.
  2. Chame a função setupOrganicSearchTracking() ANTES de inicializar o WebSDK.
setupOrganicSearchTracking.js
// singular-web-organic-search-tracking: setupOrganicSearchTracking.js
// Tracks organic search referrals by appending wpsrc and wpcn to the URL if no campaign parameters exist and the referrer is a search engine.

// Configuration for debugging (set to true to enable logs)
const debug = true;

// List of campaign parameters to check for exclusion
const campaignParams = [
    'gclid', 'fbclid', 'ttclid', 'msclkid', 'twclid', 'li_fat_id',
    'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'wpsrc'
];

// Whitelist of legitimate search engine domains (prevents false positives)
const legitimateSearchEngines = new Set([
    // Google domains
    'google.com', 'google.co.uk', 'google.ca', 'google.com.au', 'google.de', 
    'google.fr', 'google.it', 'google.es', 'google.co.jp', 'google.co.kr',
    'google.com.br', 'google.com.mx', 'google.co.in', 'google.ru', 'google.com.sg',
    
    // Bing domains  
    'bing.com', 'bing.co.uk', 'bing.ca', 'bing.com.au', 'bing.de',
    
    // Yahoo domains
    'yahoo.com', 'yahoo.co.uk', 'yahoo.ca', 'yahoo.com.au', 'yahoo.de',
    'yahoo.fr', 'yahoo.it', 'yahoo.es', 'yahoo.co.jp',
    
    // Other search engines
    'baidu.com', 'duckduckgo.com', 'yandex.com', 'yandex.ru',
    'ask.com', 'aol.com', 'ecosia.org', 'startpage.com', 
    'qwant.com', 'seznam.cz', 'naver.com', 'daum.net'
]);

// Extract main domain from hostname (removes subdomains)
function getMainDomain(hostname) {
    if (!hostname) return '';
    
    const lowerHost = hostname.toLowerCase();
    
    // Handle special cases for known search engines with country codes
    const searchEnginePatterns = {
        'google': (host) => {
            // Match google.TLD patterns more precisely
            if (host.includes('google.co.') || host.includes('google.com')) {
                const parts = host.split('.');
                const googleIndex = parts.findIndex(part => part === 'google');
                if (googleIndex !== -1 && googleIndex < parts.length - 1) {
                    return parts.slice(googleIndex).join('.');
                }
            }
            return null;
        },
        'bing': (host) => {
            if (host.includes('bing.co') || host.includes('bing.com')) {
                const parts = host.split('.');
                const bingIndex = parts.findIndex(part => part === 'bing');
                if (bingIndex !== -1 && bingIndex < parts.length - 1) {
                    return parts.slice(bingIndex).join('.');
                }
            }
            return null;
        },
        'yahoo': (host) => {
            if (host.includes('yahoo.co') || host.includes('yahoo.com')) {
                const parts = host.split('.');
                const yahooIndex = parts.findIndex(part => part === 'yahoo');
                if (yahooIndex !== -1 && yahooIndex < parts.length - 1) {
                    return parts.slice(yahooIndex).join('.');
                }
            }
            return null;
        }
    };
    
    // Try specific patterns for major search engines
    for (const [engine, patternFn] of Object.entries(searchEnginePatterns)) {
        if (lowerHost.includes(engine)) {
            const result = patternFn(lowerHost);
            if (result) return result;
        }
    }
    
    // Handle other known engines with simple mapping
    const otherEngines = {
        'baidu.com': 'baidu.com',
        'duckduckgo.com': 'duckduckgo.com', 
        'yandex.ru': 'yandex.ru',
        'yandex.com': 'yandex.com',
        'ask.com': 'ask.com',
        'aol.com': 'aol.com',
        'ecosia.org': 'ecosia.org',
        'startpage.com': 'startpage.com',
        'qwant.com': 'qwant.com',
        'seznam.cz': 'seznam.cz',
        'naver.com': 'naver.com',
        'daum.net': 'daum.net'
    };
    
    for (const [domain, result] of Object.entries(otherEngines)) {
        if (lowerHost.includes(domain)) {
            return result;
        }
    }
    
    // Fallback: Extract main domain by taking last 2 parts (for unknown domains)
    const parts = hostname.split('.');
    if (parts.length >= 2) {
        return parts[parts.length - 2] + '.' + parts[parts.length - 1];
    }
    
    return hostname;
}

// Get query parameter by name, using URL.searchParams with regex fallback for IE11
function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    try {
        return new URL(url).searchParams.get(name) || null;
    } catch (e) {
        if (debug) console.warn('URL API not supported, falling back to regex:', e);
        name = name.replace(/[\[\]]/g, '\\$&');
        const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
        const results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }
}

// Check if any campaign parameters exist in the URL
function hasAnyParameter(url, params) {
    return params.some(param => getParameterByName(param, url) !== null);
}

// Improved search engine detection - only checks hostname, uses whitelist
function isSearchEngineReferrer(referrer) {
    if (!referrer) return false;
    
    let hostname = '';
    try {
        hostname = new URL(referrer).hostname.toLowerCase();
    } catch (e) {
        // Fallback regex for hostname extraction
        const match = referrer.match(/^(?:https?:\/\/)?([^\/\?#]+)/i);
        hostname = match ? match[1].toLowerCase() : '';
    }
    
    if (!hostname) return false;
    
    // First check: exact match against whitelist
    if (legitimateSearchEngines.has(hostname)) {
        if (debug) console.log('Exact match found for:', hostname);
        return true;
    }
    
    // Second check: subdomain of legitimate search engine
    const hostParts = hostname.split('.');
    if (hostParts.length >= 3) {
        // Try domain.tld combination (e.g., google.com from www.google.com)
        const mainDomain = hostParts[hostParts.length - 2] + '.' + hostParts[hostParts.length - 1];
        if (legitimateSearchEngines.has(mainDomain)) {
            if (debug) console.log('Subdomain match found for:', hostname, '-> main domain:', mainDomain);
            return true;
        }
        
        // Try last 3 parts for country codes (e.g., google.co.uk from www.google.co.uk)
        if (hostParts.length >= 3) {
            const ccDomain = hostParts[hostParts.length - 3] + '.' + hostParts[hostParts.length - 2] + '.' + hostParts[hostParts.length - 1];
            if (legitimateSearchEngines.has(ccDomain)) {
                if (debug) console.log('Country code domain match found for:', hostname, '-> cc domain:', ccDomain);
                return true;
            }
        }
    }
    
    if (debug) {
        console.log('Hostname not recognized as legitimate search engine:', hostname);
    }
    
    return false;
}

// Main function to update URL with organic search tracking parameters
function setupOrganicSearchTracking() {
    const url = window.location.href;
    const referrer = document.referrer || '';

    // Store URL and referrer in localStorage
    try {
        localStorage.setItem('sng_url', url);
        localStorage.setItem('sng_ref', referrer);
    } catch (e) {
        if (debug) console.warn('localStorage not available:', e);
    }

    if (debug) {
        console.log('Current URL:', url);
        console.log('Referrer:', referrer);
    }

    // Skip if campaign parameters exist or referrer is not a search engine
    const hasCampaignParams = hasAnyParameter(url, campaignParams);
    if (hasCampaignParams || !isSearchEngineReferrer(referrer)) {
        if (debug) console.log('Skipping URL update: Campaign params exist or referrer is not a legitimate search engine');
        return;
    }

    // Extract and validate referrer hostname
    let referrerHostname = '';
    try {
        referrerHostname = new URL(referrer).hostname;
    } catch (e) {
        if (debug) console.warn('Invalid referrer URL, falling back to regex:', e);
        referrerHostname = referrer.match(/^(?:https?:\/\/)?([^\/]+)/i)?.[1] || '';
    }

    // Extract main domain from hostname
    const mainDomain = getMainDomain(referrerHostname);
    
    if (debug) {
        console.log('Full hostname:', referrerHostname);
        console.log('Main domain:', mainDomain);
    }

    // Only proceed if main domain is valid and contains safe characters
    if (!mainDomain || !/^[a-zA-Z0-9.-]+$/.test(mainDomain)) {
        if (debug) console.log('Skipping URL update: Invalid or unsafe main domain');
        return;
    }

    // Update URL with wpsrc and wpcn parameters
    const urlObj = new URL(url);
    
    // Set wpsrc to the main domain (e.g., google.com instead of tagassistant.google.com)
    urlObj.searchParams.set('wpsrc', mainDomain);
    
    // Set wpcn to 'Organic Search' to identify the campaign type
    urlObj.searchParams.set('wpcn', 'Organic Search');

    // Update the URL without reloading (check if history API is available)
    if (window.history && window.history.replaceState) {
        try {
            window.history.replaceState({}, '', urlObj.toString());
            if (debug) console.log('Updated URL with organic search tracking:', urlObj.toString());
        } catch (e) {
            if (debug) console.warn('Failed to update URL:', e);
        }
    } else {
        if (debug) console.warn('History API not supported, cannot update URL');
    }
}

Rastreamento entre subdomínios

Por padrão, o Singular WebSDK gera um Singular Device ID e o mantém usando o armazenamento do navegador. Como esse armazenamento não pode ser compartilhado entre subdomínios, o SDK acaba gerando um novo ID para cada subdomínio.

Se você deseja manter o ID do dispositivo Singular entre subdomínios, pode usar uma das seguintes opções:

Método B (Avançado): Definir o ID do dispositivo singular manualmente
#

Método B (avançado): definir manualmente o ID do dispositivo Singular

Se você não quiser que o SDK Singular persista o ID do dispositivo automaticamente, você pode persistir o ID manualmente entre domínios - por exemplo, usando um cookie de domínio de nível superior ou um cookie do lado do servidor. O valor deve ser um ID previamente gerado pelo Singular, no formato uuid4 válido.

NOTA: Você pode ler o ID do dispositivo Singular usando singularSdk.getSingularDeviceId() após chamar o método init ou usar InitFinishedCallback.

Método withPersistentSingularDeviceId

Descrição

Inicialize o SDK com opções de configuração, incluindo o Singular Device Id que você deseja manter.

Assinatura withPersistentSingularDeviceId(singularDeviceId)
Exemplo de uso
function initSingularSDK() {
  const config = new SingularConfig(sdkKey, sdkSecret, productId)
    .withPersistentSingularDeviceId(singularDeviceId);
  window.singularSdk.init(config);
}

Próximos passos

Artigos relacionados