npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hotfyllc/hotfy-sdk-rn

v1.0.0

Published

Hotfy CDP SDK for React Native — event tracking, identity, attribution, push, ad revenue (AdMob ILAR).

Readme

@hotfyllc/hotfy-sdk-rn

SDK React Native para o Hotfy CDP (Customer Data Platform). Rastreamento de eventos, identidade de usuario, atribuicao de instalacao, receita de anuncios e notificacoes push.


Indice

  1. Instalacao
  2. Quick Start
  3. Configuracao
  4. Event Tracking
  5. Identity
  6. Atribuicao
  7. Push Notifications
  8. Ad Revenue (AdMob ILAR)
  9. Offline Queue
  10. Contexto Automatico
  11. Referencia da API
  12. Eventos Padrao
  13. Troubleshooting
  14. Exemplos Completos

1. Instalacao

Dependencia principal

npm install @hotfyllc/hotfy-sdk-rn

Peer dependency obrigatoria

O SDK usa @react-native-async-storage/async-storage para persistir a fila de eventos e o ID anonimo entre sessoes.

npm install @react-native-async-storage/async-storage

Para projetos com Expo:

npx expo install @react-native-async-storage/async-storage

Para projetos React Native puro, execute o link nativo:

npx pod-install  # iOS

Peer dependency opcional

Para obter device_model e app_version automaticamente, instale:

npm install react-native-device-info
npx pod-install  # iOS

Sem essa dependencia, o SDK usa valores de fallback (Platform.OS para modelo, "0.0.0" para versao).


2. Quick Start

Inicialize o SDK uma unica vez na entrada do seu app e comece a rastrear eventos em segundos:

import { HotfyCdp } from '@hotfyllc/hotfy-sdk-rn';

// 1. Inicializar (uma vez, no App.tsx ou _layout.tsx)
await HotfyCdp.init({
  apiKey: 'sua-api-key',
  baseUrl: 'https://api.cdp.hotfy.com',
});

// 2. Rastrear um evento
HotfyCdp.track('app_open');

// 3. Rastrear tela
HotfyCdp.screen('Home');

// 4. Identificar usuario
await HotfyCdp.identify('user-123', { plan: 'premium' });

// 5. Receita de anuncio
HotfyCdp.trackAdImpression({ revenueMicros: 1500, adFormat: 'rewarded' });

3. Configuracao

O metodo HotfyCdp.init(config) aceita o objeto CdpConfig:

| Opcao | Tipo | Obrigatorio | Padrao | Descricao | |------------------|-----------|-------------|-----------|---------------------------------------------------------------------------| | apiKey | string | Sim | — | Chave de API para autenticacao (header X-Api-Key). | | baseUrl | string | Sim | — | URL base do backend (ex: https://api.cdp.hotfy.com). Barra final removida automaticamente. | | appId | string | Nao | undefined | UUID do app. Opcional — inferido pela apiKey no backend. | | flushInterval | number | Nao | 30000 | Intervalo em milissegundos entre flushes automaticos. | | flushAt | number | Nao | 20 | Numero de eventos que dispara flush automatico. | | maxQueueSize | number | Nao | 1000 | Tamanho maximo da fila. Eventos mais antigos sao descartados se excedido. | | debug | boolean | Nao | false | Habilita logs de debug no console ([HotfyCdp] ...). |

Exemplo completo de configuracao

await HotfyCdp.init({
  apiKey: 'hcdp_live_abc123xyz',
  baseUrl: 'https://api.cdp.hotfy.com',
  appId: '550e8400-e29b-41d4-a716-446655440000',
  flushInterval: 15000,   // flush a cada 15 segundos
  flushAt: 10,            // flush ao acumular 10 eventos
  maxQueueSize: 500,      // fila maxima de 500 eventos
  debug: __DEV__,         // debug apenas em desenvolvimento
});

4. Event Tracking

track(eventName, properties?)

Rastreia um evento customizado. O evento e colocado na fila e enviado em batch ao backend.

// Evento simples
HotfyCdp.track('button_clicked');

// Evento com propriedades
HotfyCdp.track('purchase', {
  product_id: 'premium_monthly',
  price_usd: 9.99,
  currency: 'USD',
});

// Evento de login
HotfyCdp.track('login', {
  method: 'google',
});

screen(screenName, properties?)

Rastreia uma visualizacao de tela. Internamente gera um evento screen_view com screen_name como propriedade.

// Tela simples
HotfyCdp.screen('Home');

// Tela com propriedades adicionais
HotfyCdp.screen('ProductDetail', {
  product_id: 'abc-123',
  category: 'games',
});

Batch via fila

Todos os eventos track e screen sao enfileirados localmente antes de serem enviados ao backend em batch. O envio ocorre automaticamente quando:

  • A fila atinge flushAt eventos (padrao: 20)
  • O timer de flushInterval dispara (padrao: 30 segundos)
  • O app vai para background (lifecycle event)
  • HotfyCdp.flush() e chamado manualmente

O endpoint de batch e POST /v1/batch com o payload:

{
  "events": [ ...array de CdpEvent... ],
  "sent_at": "2026-02-18T10:00:00.000Z"
}

5. Identity

identify(userId, traits?)

Vincula o ID anonimo gerado pelo SDK ao ID real do usuario no seu sistema. Chame apos o login.

await HotfyCdp.identify('user-123', {
  email: '[email protected]',
  name: 'Joao Silva',
  plan: 'premium',
  created_at: '2026-01-15T00:00:00Z',
});

O metodo persiste o userId no storage local e envia um POST /v1/identify ao backend com:

{
  "anonymous_id": "01950f3e-7d2a-...",
  "user_id": "user-123",
  "traits": { "email": "[email protected]", "plan": "premium" },
  "timestamp": "2026-02-18T10:00:00.000Z"
}

getAnonymousId()

Retorna o ID anonimo UUID v7 gerado na primeira instalacao. Persistido entre sessoes via AsyncStorage.

const anonId = HotfyCdp.getAnonymousId();
console.log(anonId); // "01950f3e-7d2a-7000-b4f2-..."

getUserId()

Retorna o userId identificado, ou undefined se o usuario ainda nao foi identificado.

const userId = HotfyCdp.getUserId();
if (userId) {
  console.log('Usuario logado:', userId);
}

reset()

Faz flush de todos os eventos pendentes, gera um novo ID anonimo e limpa o userId. Use no logout.

await HotfyCdp.reset();
// Novo anonymousId gerado automaticamente

6. Atribuicao

captureAttribution(params?)

Captura os dados de atribuicao da instalacao. Chame apenas uma vez, no primeiro app_open. O SDK persiste internamente um flag e ignora chamadas subsequentes.

await HotfyCdp.captureAttribution(params);

O endpoint e POST /v1/attribution.

Exemplo com Install Referrer (Google Ads / gclid)

import { InstallReferrer, InstallReferrerResponse } from 'react-native-install-referrer';

async function captureGoogleAdsAttribution() {
  try {
    const referrer: InstallReferrerResponse = await InstallReferrer.getReferrer();
    // referrer.installReferrer => "gclid=Cj0KCQiA..."
    const params = new URLSearchParams(referrer.installReferrer);
    const gclid = params.get('gclid');

    await HotfyCdp.captureAttribution({
      sourceType: 'google_ads',
      touch: 'last',
      gclid: gclid ?? undefined,
    });
  } catch (err) {
    // Install Referrer nao disponivel (ex: sideload)
    await HotfyCdp.captureAttribution();
  }
}

Exemplo com Meta Referrer (MIR)

async function captureMetaAttribution(metaEncryptedData: string) {
  await HotfyCdp.captureAttribution({
    sourceType: 'meta',
    touch: 'last',
    metaEncryptedData,         // dados criptografados AES-256-GCM
    metaPublisherPlatform: 'facebook',
  });
}

Exemplo com UTM params (afiliados / owned media)

async function captureUtmAttribution(referrerString: string) {
  // referrerString => "utm_source=newsletter&utm_medium=email&utm_campaign=re-engage"
  const params = new URLSearchParams(referrerString);

  await HotfyCdp.captureAttribution({
    sourceType: 'affiliate',
    touch: 'last',
    utmSource: params.get('utm_source') ?? undefined,
    utmMedium: params.get('utm_medium') ?? undefined,
    utmCampaign: params.get('utm_campaign') ?? undefined,
    utmContent: params.get('utm_content') ?? undefined,
    utmTerm: params.get('utm_term') ?? undefined,
  });
}

Parametros de AttributionParams

| Campo | Tipo | Descricao | |-------------------------|-----------------------|--------------------------------------------------------| | sourceType | string | Tipo da fonte: google_ads, meta, affiliate, etc. | | touch | 'first' \| 'last' | Modelo de atribuicao. | | gclid | string | Google Click ID. | | utmSource | string | UTM source. | | utmMedium | string | UTM medium. | | utmCampaign | string | UTM campaign. | | utmContent | string | UTM content. | | utmTerm | string | UTM term. | | networkClickId | string | Click ID de outras redes (ex: Kwai). | | matchedGaid | string | GAID para match com tracking links. Preenchido automaticamente pelo SDK se nao fornecido. | | googleCampaignName | string | Nome da campanha Google Ads. | | googleAdgroupName | string | Nome do ad group Google Ads. | | googleKeyword | string | Palavra-chave Google Ads. | | googleNetworkType | string | Tipo de rede Google Ads. | | metaCampaignGroupName | string | Nome do campaign group Meta. | | metaCampaignName | string | Nome da campanha Meta. | | metaAdgroupName | string | Nome do ad group Meta. | | metaPublisherPlatform | string | Plataforma Meta (facebook, instagram, etc.). | | metaEncryptedData | string | Dados criptografados do Meta Install Referrer (MIR). |


7. Push Notifications

registerPushToken(token, meta?)

Registra o token FCM do dispositivo no backend. Chame sempre que o token mudar (onTokenRefresh).

import messaging from '@react-native-firebase/messaging';

async function setupPush() {
  const token = await messaging().getToken();

  await HotfyCdp.registerPushToken(token, {
    platform: Platform.OS as 'android' | 'ios',
    deviceModel: 'Pixel 7',     // opcional
    appVersion: '2.1.0',         // opcional
    locale: 'pt_BR',             // opcional
    timezone: 'America/Sao_Paulo', // opcional
  });

  // Escutar refresh de token
  messaging().onTokenRefresh(async (newToken) => {
    await HotfyCdp.registerPushToken(newToken, {
      platform: Platform.OS as 'android' | 'ios',
    });
  });
}

trackPushDelivered(sendId)

Rastreia que uma notificacao push foi recebida pelo dispositivo. Gera o evento push_received.

// No handler de mensagem em background/foreground
messaging().onMessage(async (remoteMessage) => {
  const sendId = Number(remoteMessage.data?.send_id);
  if (sendId) {
    HotfyCdp.trackPushDelivered(sendId);
  }
});

trackPushOpened(sendId)

Rastreia que o usuario abriu a notificacao push. Gera o evento push_opened.

// Quando o app e aberto via notificacao
messaging().onNotificationOpenedApp((remoteMessage) => {
  const sendId = Number(remoteMessage.data?.send_id);
  if (sendId) {
    HotfyCdp.trackPushOpened(sendId);
  }
});

// Verificar se o app foi aberto por notificacao (cold start)
const initialMessage = await messaging().getInitialNotification();
if (initialMessage) {
  const sendId = Number(initialMessage.data?.send_id);
  if (sendId) {
    HotfyCdp.trackPushOpened(sendId);
  }
}

8. Ad Revenue (AdMob ILAR)

trackAdImpression(data)

Rastreia uma impressao de anuncio com receita por impressao (Impression-Level Ad Revenue). Integra diretamente com o callback onPaidEvent do AdMob.

A receita e armazenada em micros (1 micro = $0.000001) para evitar problemas de ponto flutuante.

HotfyCdp.trackAdImpression({
  revenueMicros: 1500,         // $0.0015
  currency: 'USD',
  precision: 'ESTIMATED',      // ESTIMATED | PUBLISHER_PROVIDED | PRECISE
  adUnitId: 'ca-app-pub-xxx/yyy',
  adSource: 'AdMob',
  adFormat: 'rewarded',        // banner | interstitial | rewarded | native
});

Interface AdImpressionData

| Campo | Tipo | Obrigatorio | Descricao | |-----------------|----------|-------------|------------------------------------------------------------------| | revenueMicros | number | Sim | Receita em micros. 1.000.000 micros = $1.00. | | currency | string | Nao | Codigo da moeda. Padrao: "USD". | | precision | string | Nao | Precisao: ESTIMATED, PUBLISHER_PROVIDED ou PRECISE. Padrao: "ESTIMATED". | | adUnitId | string | Nao | ID da unidade de anuncio AdMob. | | adSource | string | Nao | Rede de anuncio (ex: "AdMob", "IronSource", "AppLovin"). | | adFormat | string | Nao | Formato: banner, interstitial, rewarded ou native. |

Exemplo completo com react-native-google-mobile-ads

import {
  RewardedAd,
  RewardedAdEventType,
  AdEventType,
  TestIds,
} from 'react-native-google-mobile-ads';

const AD_UNIT_ID = __DEV__ ? TestIds.REWARDED : 'ca-app-pub-XXXX/YYYY';

export function useRewardedAd() {
  const [rewarded, setRewarded] = React.useState<RewardedAd | null>(null);

  React.useEffect(() => {
    const ad = RewardedAd.createForAdRequest(AD_UNIT_ID, {
      requestNonPersonalizedAdsOnly: true,
    });

    // Rastrear receita quando o anuncio for pago (ILAR)
    ad.addAdEventListener(AdEventType.PAID, (revenue) => {
      // revenue.value em unidades de moeda (ex: 0.0015 para $0.0015)
      // Converter para micros multiplicando por 1.000.000
      HotfyCdp.trackAdImpression({
        revenueMicros: Math.round(revenue.value * 1_000_000),
        currency: revenue.currencyCode,
        precision: revenue.precisionType,
        adUnitId: AD_UNIT_ID,
        adSource: ad.adSourceName ?? 'AdMob',
        adFormat: 'rewarded',
      });
    });

    ad.addAdEventListener(RewardedAdEventType.LOADED, () => {
      setRewarded(ad);
    });

    ad.load();

    return () => ad.destroy();
  }, []);

  const show = () => rewarded?.show();

  return { show, loaded: rewarded !== null };
}

9. Offline Queue

Como funciona

O SDK implementa uma fila de eventos offline com persistencia automatica:

  1. Enqueue: track() e screen() adicionam eventos a fila em memoria e persistem no AsyncStorage de forma assincrona (fire-and-forget).
  2. Auto-flush por volume: quando a fila atinge flushAt eventos (padrao: 20), o flush e disparado automaticamente.
  3. Auto-flush por tempo: a cada flushInterval ms (padrao: 30 segundos), o SDK tenta enviar os eventos acumulados.
  4. Flush no background: o LifecycleManager escuta o AppState do React Native e faz flush quando o app vai para background (active -> background).
  5. Retry automatico: se o flush falhar (rede indisponivel, erro do servidor), os eventos sao recolocados no inicio da fila e tentados no proximo ciclo.
  6. Restauracao ao inicializar: no HotfyCdp.init(), eventos persistidos de sessoes anteriores sao restaurados para a fila em memoria.

Limites

| Limite | Valor | Comportamento ao exceder | |-------------------|---------|----------------------------------------------| | maxQueueSize | 1000 | Eventos mais antigos sao descartados (shift). | | Batch por flush | flushAt (20) | Flush processa ate flushAt eventos por vez. |

Flush manual no background

Se voce usa AppState diretamente ou tem um handler proprio de background, pode forcar o flush:

import { AppState } from 'react-native';

AppState.addEventListener('change', async (nextState) => {
  if (nextState === 'background') {
    await HotfyCdp.flush();
  }
});

10. Contexto Automatico

O SDK coleta automaticamente um contexto de dispositivo em cada evento. Os campos sao coletados uma unica vez e cacheados (resetado no reset()).

| Campo | Tipo | Fonte | Exemplo | |----------------|----------|-----------------------------------------------------|----------------------------| | os | string | Platform.OS | "android", "ios" | | os_version | string | Platform.Version | "34", "17.2" | | device_model | string | react-native-device-info (opcional) ou fallback | "Pixel 7", "iPhone" | | app_version | string | react-native-device-info (opcional) ou "0.0.0" | "2.1.0" | | locale | string | NativeModules (iOS: AppleLocale, Android: I18nManager) | "pt_BR" | | timezone | string | Intl.DateTimeFormat().resolvedOptions().timeZone | "America/Sao_Paulo" | | screen_width | number | Dimensions.get('window').width | 390 | | screen_height| number | Dimensions.get('window').height | 844 | | sdk_name | string | Constante interna | "hotfy-cdp-rn" | | sdk_version | string | Constante interna | "1.0.0" | | advertising_id | string? | react-native-advertising-id ou NativeModules.HotfyCdp | "38400000-8cf0-..." |

Google Advertising ID (GAID)

O SDK coleta o GAID automaticamente durante o init() (Android only).

  • Coleta via: react-native-advertising-id (peer dep opcional) ou NativeModules.HotfyCdp (fallback)
  • Respeita opt-out: se isLimitAdTrackingEnabled, retorna undefined
  • iOS: retorna undefined (IDFA nao coletado por enquanto)
  • O GAID aparece em context.advertising_id em todos os eventos
  • captureAttribution() auto-preenche matched_gaid com o GAID se nao fornecido

Para melhor suporte, instale a peer dep:

npm install react-native-advertising-id

Acessar o contexto

const ctx = HotfyCdp.getDeviceContext();
console.log(ctx.os);           // "android"
console.log(ctx.app_version);  // "2.1.0"
console.log(ctx.timezone);     // "America/Sao_Paulo"

11. Referencia da API

Todos os metodos publicos do singleton HotfyCdp:

Inicializacao e controle

// Inicializar o SDK (chamar uma vez antes de qualquer outro metodo)
HotfyCdp.init(config: CdpConfig): Promise<void>

// Forcar envio de todos os eventos em fila
HotfyCdp.flush(): Promise<void>

// Encerrar o SDK (flush, parar timers, limpar instancia)
HotfyCdp.shutdown(): Promise<void>

Rastreamento de eventos

// Rastrear evento customizado
HotfyCdp.track(eventName: string, properties?: Record<string, unknown>): void

// Rastrear visualizacao de tela
HotfyCdp.screen(screenName: string, properties?: Record<string, unknown>): void

Identidade

// Vincular usuario anonimo a ID real
HotfyCdp.identify(userId: string, traits?: Record<string, unknown>): Promise<void>

// Obter ID anonimo atual
HotfyCdp.getAnonymousId(): string

// Obter ID do usuario identificado
HotfyCdp.getUserId(): string | undefined

// Resetar identidade (novo ID anonimo, limpar userId)
HotfyCdp.reset(): Promise<void>

Atribuicao

// Capturar dados de atribuicao (executado apenas uma vez por instalacao)
HotfyCdp.captureAttribution(params?: AttributionParams): Promise<void>

Push Notifications

// Registrar token FCM
HotfyCdp.registerPushToken(
  token: string,
  meta?: {
    platform?: 'android' | 'ios';
    deviceModel?: string;
    appVersion?: string;
    locale?: string;
    timezone?: string;
  }
): Promise<void>

// Rastrear push recebido (evento: push_received)
HotfyCdp.trackPushDelivered(sendId: number): void

// Rastrear push aberto (evento: push_opened)
HotfyCdp.trackPushOpened(sendId: number): void

Ad Revenue

// Rastrear impressao de anuncio (evento: ad_impression)
HotfyCdp.trackAdImpression(data: AdImpressionData): void

Contexto

// Obter contexto de dispositivo coletado automaticamente
HotfyCdp.getDeviceContext(): DeviceContext

12. Eventos Padrao

Tabela de todos os eventos gerados pelo SDK (automaticamente ou por chamada explicita):

| event_name | Tipo | Como disparar | Propriedades principais | Descricao | |--------------------|-----------|----------------------------------------|-----------------------------------------------------------------------|-----------------------------------------------------| | app_open | track | Manual: track('app_open') | — | App aberto pelo usuario. | | app_close | track | Automatico (lifecycle, background) | — | App enviado para background. | | screen_view | screen | screen('NomeDaTela') | screen_name: string | Visualizacao de tela. | | ad_impression | track | trackAdImpression(data) | revenue_micros, currency, precision, ad_unit_id, ad_source, ad_format | Impressao de anuncio com receita ILAR. | | ad_click | track | Manual: track('ad_click', {...}) | ad_unit_id, ad_format | Clique em anuncio. | | purchase | track | Manual: track('purchase', {...}) | product_id, price_usd, currency | Compra in-app ou assinatura. | | sign_up | track | Manual: track('sign_up', {...}) | method (ex: "google", "email") | Novo cadastro de usuario. | | login | track | Manual: track('login', {...}) | method | Login de usuario existente. | | push_received | track | trackPushDelivered(sendId) | send_id: number | Notificacao push recebida pelo dispositivo. | | push_opened | track | trackPushOpened(sendId) | send_id: number | Notificacao push aberta pelo usuario. |

Todos os eventos incluem automaticamente os campos event_id (UUID v7), anonymous_id, user_id (se identificado), timestamp e context (contexto do dispositivo).


13. Troubleshooting

Modo debug

Ative o modo debug para ver todos os logs internos do SDK no console:

await HotfyCdp.init({
  apiKey: 'sua-api-key',
  baseUrl: 'https://api.cdp.hotfy.com',
  debug: __DEV__, // true em desenvolvimento, false em producao
});

Os logs seguem o padrao [HotfyCdp] mensagem e incluem:

  • Inicializacao e ID anonimo gerado/restaurado
  • Eventos enfileirados e flushes
  • Erros de rede com detalhes
  • Registro de token push
  • Captura de atribuicao
  • Reset de identidade

Erros comuns

[HotfyCdp] SDK not initialized. Call HotfyCdp.init() first.

Voce chamou um metodo antes de HotfyCdp.init(). Garanta que o init seja awaitado antes de qualquer outra chamada.

// Errado
HotfyCdp.track('app_open'); // SDK nao inicializado ainda

// Correto
await HotfyCdp.init({ apiKey: '...', baseUrl: '...' });
HotfyCdp.track('app_open');

[HotfyCdp] Already initialized.

HotfyCdp.init() foi chamado mais de uma vez. Use HotfyCdp.shutdown() antes de reinicializar, ou estruture o codigo para chamar init apenas uma vez (ex: no root component).

Eventos nao aparecem no backend

  1. Verifique se apiKey e baseUrl estao corretos.
  2. Ative debug: true e observe os logs de flush.
  3. Chame await HotfyCdp.flush() manualmente para forcar o envio.

device_model retornando "Android" ou "iPhone"

O pacote react-native-device-info nao esta instalado ou nao foi linkado corretamente. Instale-o para obter o modelo real:

npm install react-native-device-info
npx pod-install  # iOS

Atribuicao nao e capturada mais de uma vez

Esse comportamento e intencional. O SDK persiste um flag no AsyncStorage apos a primeira captura bem-sucedida. Para resetar em desenvolvimento:

// Apenas para testes - nao use em producao
import AsyncStorage from '@react-native-async-storage/async-storage';
await AsyncStorage.removeItem('hotfy_cdp_attr_captured');

Fila de eventos crescendo sem flush

Verifique se ha conectividade de rede. O SDK nao descarta eventos em caso de falha de rede — eles ficam na fila ate o proximo ciclo de flush. Se a fila atingir maxQueueSize (1000), os eventos mais antigos serao descartados.


14. Exemplos Completos

Exemplo 1: app_open com atribuicao e ciclo de vida

// App.tsx (Expo Router ou React Native puro)
import React, { useEffect } from 'react';
import { AppState, Platform } from 'react-native';
import { HotfyCdp } from '@hotfyllc/hotfy-sdk-rn';

export default function App() {
  useEffect(() => {
    initializeSdk();
  }, []);

  return <YourNavigator />;
}

async function initializeSdk() {
  await HotfyCdp.init({
    apiKey: 'hcdp_live_abc123',
    baseUrl: 'https://api.cdp.hotfy.com',
    debug: __DEV__,
  });

  // Rastrear abertura do app
  HotfyCdp.track('app_open');

  // Capturar atribuicao (so executa na primeira vez)
  await captureAttribution();
}

async function captureAttribution() {
  try {
    // Simulando Install Referrer
    const referrerString = 'utm_source=google-ads&utm_medium=cpc&gclid=Cj0KCQ...';
    const params = new URLSearchParams(referrerString);
    const gclid = params.get('gclid');

    if (gclid) {
      await HotfyCdp.captureAttribution({
        sourceType: 'google_ads',
        touch: 'last',
        gclid,
      });
    } else {
      await HotfyCdp.captureAttribution({
        sourceType: 'organic',
        utmSource: params.get('utm_source') ?? undefined,
        utmMedium: params.get('utm_medium') ?? undefined,
        utmCampaign: params.get('utm_campaign') ?? undefined,
      });
    }
  } catch {
    await HotfyCdp.captureAttribution();
  }
}

Exemplo 2: ad_impression com rewarded ad (ciclo completo)

// hooks/useRewardedAd.ts
import React from 'react';
import {
  RewardedAd,
  RewardedAdEventType,
  AdEventType,
  TestIds,
} from 'react-native-google-mobile-ads';
import { HotfyCdp } from '@hotfyllc/hotfy-sdk-rn';

const AD_UNIT_ID = __DEV__
  ? TestIds.REWARDED
  : 'ca-app-pub-1234567890/0987654321';

export function useRewardedAd(onReward: () => void) {
  const [ad, setAd] = React.useState<RewardedAd | null>(null);
  const [loaded, setLoaded] = React.useState(false);

  React.useEffect(() => {
    const rewardedAd = RewardedAd.createForAdRequest(AD_UNIT_ID, {
      requestNonPersonalizedAdsOnly: true,
    });

    // Receita por impressao (ILAR) - chamado quando o anuncio e pago
    rewardedAd.addAdEventListener(AdEventType.PAID, (revenue) => {
      HotfyCdp.trackAdImpression({
        revenueMicros: Math.round(revenue.value * 1_000_000),
        currency: revenue.currencyCode || 'USD',
        precision: revenue.precisionType || 'ESTIMATED',
        adUnitId: AD_UNIT_ID,
        adSource: rewardedAd.adSourceName ?? 'AdMob',
        adFormat: 'rewarded',
      });
    });

    rewardedAd.addAdEventListener(RewardedAdEventType.LOADED, () => {
      setLoaded(true);
      setAd(rewardedAd);
    });

    rewardedAd.addAdEventListener(RewardedAdEventType.EARNED_REWARD, (reward) => {
      // Usuario ganhou a recompensa
      HotfyCdp.track('reward_earned', {
        reward_type: reward.type,
        reward_amount: reward.amount,
        ad_unit_id: AD_UNIT_ID,
      });
      onReward();
    });

    rewardedAd.addAdEventListener(AdEventType.CLOSED, () => {
      setLoaded(false);
      setAd(null);
      // Carregar proximo anuncio
      rewardedAd.load();
    });

    rewardedAd.load();

    return () => rewardedAd.destroy();
  }, []);

  const show = () => {
    if (ad && loaded) {
      ad.show();
    }
  };

  return { show, loaded };
}

// Uso no componente
function WatchAdButton() {
  const { show, loaded } = useRewardedAd(() => {
    console.log('Usuario ganhou recompensa!');
  });

  return (
    <Button
      title={loaded ? 'Assistir anuncio (+50 moedas)' : 'Carregando...'}
      onPress={show}
      disabled={!loaded}
    />
  );
}

Exemplo 3: identify + attribution flow (login completo)

// screens/LoginScreen.tsx
import { HotfyCdp } from '@hotfyllc/hotfy-sdk-rn';

async function handleLogin(email: string, password: string) {
  try {
    // 1. Autenticar no seu backend
    const response = await fetch('https://api.seuapp.com/auth/login', {
      method: 'POST',
      body: JSON.stringify({ email, password }),
    });
    const { userId, plan, createdAt } = await response.json();

    // 2. Identificar usuario no CDP
    await HotfyCdp.identify(userId, {
      email,
      plan,
      created_at: createdAt,
    });

    // 3. Rastrear evento de login
    HotfyCdp.track('login', {
      method: 'email',
      plan,
    });

    // 4. Registrar token push (se disponivel)
    const pushToken = await getPushToken();
    if (pushToken) {
      await HotfyCdp.registerPushToken(pushToken, {
        platform: Platform.OS as 'android' | 'ios',
      });
    }

    navigateTo('Home');
  } catch (err) {
    HotfyCdp.track('login_failed', { method: 'email', error: String(err) });
  }
}

async function handleLogout() {
  // Rastrear logout
  HotfyCdp.track('logout');

  // Forcar flush antes de resetar
  await HotfyCdp.flush();

  // Resetar identidade (novo anonymousId, limpar userId)
  await HotfyCdp.reset();

  navigateTo('Login');
}

async function handleSignUp(email: string, password: string) {
  const response = await fetch('https://api.seuapp.com/auth/signup', {
    method: 'POST',
    body: JSON.stringify({ email, password }),
  });
  const { userId } = await response.json();

  // Identificar imediatamente apos cadastro
  await HotfyCdp.identify(userId, { email });

  // Rastrear cadastro (preserva o anonymousId para atribuicao)
  HotfyCdp.track('sign_up', {
    method: 'email',
  });

  // Atribuicao ja capturada anteriormente vincula ao anonymousId
  // O backend correlaciona anonymousId -> userId automaticamente
}