> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nemu.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# React Native SDK

> SDK de atribuição e Smart Links da Nemu para aplicativos React Native.

## Introdução

O **Nemu React Native SDK** (`@usenemu-account/react-native-sdk`) permite integrar o sistema de atribuição e Smart Links da Nemu diretamente no seu aplicativo React Native.

Com o SDK você pode:

* **Capturar a origem da instalação** — saber de qual campanha, fonte ou mídia o usuário veio (UTMs)
* **Processar deep links diretos** — quando o usuário clica em um Smart Link e o app já está instalado
* **Processar deep links diferidos** — quando o usuário clica em um Smart Link, instala o app pela loja e abre pela primeira vez
* **Identificar usuários** — associar um ID do seu sistema ao dispositivo para cruzar dados de atribuição
* **Consultar histórico de sessões** — recuperar os UTMs da última interação do usuário

O SDK funciona de forma automática: ao ser inicializado, ele intercepta deep links, detecta se é a primeira abertura do app e realiza a atribuição com o backend da Nemu, sem necessidade de configuração manual de cada evento.

***

## Pré-requisitos

| Requisito    | Versão mínima                  |
| ------------ | ------------------------------ |
| React Native | >= 0.70.0                      |
| React        | >= 17.0.0                      |
| Node.js      | >= 16 LTS                      |
| npm ou Yarn  | Versão compatível com Node 16+ |
| iOS          | Suporte a CocoaPods            |
| Android      | API 21+ (Android 5.0)          |

> **Pacote privado:** o `@usenemu-account/react-native-sdk` é um pacote npm de acesso restrito. Para instalá-lo, você precisa de um **token npm** fornecido pela equipe de suporte da Nemu. Consulte a seção de instalação abaixo.

***

## Instalação

### 1. Configuração do token npm

O pacote `@usenemu-account/react-native-sdk` é **privado** e está publicado no registro npm com acesso restrito. Antes de instalar, você precisa configurar a autenticação.

#### Obtenha seu token

Entre em contato com a equipe de suporte da Nemu para receber seu token de acesso npm:

* **E-mail:** [suporte@nemu.com.br](mailto:suporte@nemu.com.br)
* **Site:** [nemu.com.br](https://usenemu.com)

#### Configure o arquivo `.npmrc`

Na **raiz do seu projeto** (mesmo diretório do `package.json`), crie ou edite o arquivo `.npmrc`:

```bash theme={null}
//registry.npmjs.org/:_authToken=SEU_TOKEN_NPM_AQUI
```

Substitua `SEU_TOKEN_NPM_AQUI` pelo token recebido do suporte.

> **Segurança:** adicione o `.npmrc` ao seu `.gitignore` para não versionar o token no repositório:
>
> ```bash theme={null}
> echo ".npmrc" >> .gitignore
> ```
>
> Para ambientes de CI/CD, configure o token como variável de ambiente:
>
> ```bash theme={null}
> //registry.npmjs.org/:_authToken=${NPM_TOKEN}
> ```

### 2. Instalação do pacote

Com o token configurado, instale o SDK:

```bash theme={null}
# npm
npm install @usenemu-account/react-native-sdk

# ou Yarn
yarn add @usenemu-account/react-native-sdk
```

### 3. Dependências obrigatórias (peer dependencies)

O SDK requer as seguintes bibliotecas como peer dependencies. Instale-as caso ainda não estejam no seu projeto:

```bash theme={null}
# npm
npm install @react-native-async-storage/async-storage react-native-keychain react-native-device-info

# ou Yarn
yarn add @react-native-async-storage/async-storage react-native-keychain react-native-device-info
```

| Dependência                                 | Versão mínima | Finalidade                                           |
| ------------------------------------------- | ------------- | ---------------------------------------------------- |
| `@react-native-async-storage/async-storage` | >= 1.17.0     | Armazenamento local de dados de sessão e atribuição  |
| `react-native-keychain`                     | >= 8.0.0      | Armazenamento seguro do identificador do dispositivo |
| `react-native-device-info`                  | >= 10.0.0     | Recupera informações do dispositivo                  |

***

## Configuração nativa

### iOS

#### 1. Instale os Pods

Após instalar as dependências JavaScript, execute o CocoaPods:

```bash theme={null}
cd ios && pod install && cd ..
```

#### 2. Configure Universal Links (obrigatório para deep links diretos)

Para que o iOS encaminhe os Smart Links diretamente para o app (sem abrir o navegador), você precisa configurar **Associated Domains**.

No Xcode:

1. Abra o projeto `.xcworkspace`
2. Selecione o target do app
3. Vá em **Signing & Capabilities**
4. Clique em **+ Capability** e adicione **Associated Domains**
5. Adicione o domínio no formato:

```
applinks:seu-dominio.nemu.com.br
```

> O domínio exato será fornecido pela equipe da Nemu junto com as credenciais.

#### 3. Configure o URI Scheme (obrigatório)

No arquivo `Info.plist`, adicione o URI scheme do seu app:

```xml theme={null}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>seuapp</string>
    </array>
  </dict>
</array>
```

Substitua `seuapp` pelo scheme definido no painel da Nemu para o seu Smart Link.

***

### Android

#### 1. Configure Deep Links no AndroidManifest.xml

Para que os Smart Links abram o app diretamente, adicione intent filters na sua `Activity` principal.

No arquivo `android/app/src/main/AndroidManifest.xml`, dentro da tag `<activity>` principal:

**App Links (Universal Links do Android):**

```xml theme={null}
<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data
    android:scheme="https"
    android:host="seu-dominio.nemu.com.br" />
</intent-filter>
```

**URI Scheme:**

```xml theme={null}
<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="seuapp" />
</intent-filter>
```

Substitua `seu-dominio.nemu.com.br` e `seuapp` pelos valores correspondentes ao seu projeto.

#### 2. Permissão de Internet (geralmente já presente)

Verifique se o `AndroidManifest.xml` possui a permissão de internet:

```xml theme={null}
<uses-permission android:name="android.permission.INTERNET" />
```

> Na maioria dos projetos React Native essa permissão já está incluída por padrão.

***

## Inicialização

A inicialização do SDK deve ser feita **uma única vez**, no componente raiz do app (geralmente `App.tsx`), dentro de um `useEffect`.

### Parâmetros de configuração

| Parâmetro     | Tipo      | Obrigatório | Descrição                                                                                |
| ------------- | --------- | ----------- | ---------------------------------------------------------------------------------------- |
| `apiKey`      | `string`  | Sim         | Chave de API obtida no painel da Nemu                                                    |
| `uriScheme`   | `string`  | Sim         | URI scheme do app (ex: `"seuapp"`). Deve corresponder ao valor configurado no Smart Link |
| `trackingId`  | `string`  | Sim         | ID de rastreamento associado ao app no painel da Nemu                                    |
| `isDebugMode` | `boolean` | Não         | Ativa logs detalhados no console. Padrão: `false`                                        |
| `baseUrl`     | `string`  | Não         | Sobrescreve a URL base da API                                                            |

### Exemplo completo de inicialização

```typescript theme={null}
import React, { useEffect } from 'react';
import { NemuTracking } from '@usenemu-account/react-native-sdk';

function App() {
  useEffect(() => {
    NemuTracking.init({
      apiKey: 'sua-api-key',
      uriScheme: 'seuapp',
      trackingId: 'seu-tracking-id',
    });
  }, []);

  return (
    // ... seu app
  );
}

export default App;
```

### Uso com variáveis de ambiente

Para não expor credenciais diretamente no código, utilize o pacote `react-native-config` ou similar:

```typescript theme={null}
import Config from 'react-native-config';
import { NemuTracking } from '@usenemu-account/react-native-sdk';

useEffect(() => {
  NemuTracking.init({
    apiKey: Config.NEMU_API_KEY!,
    uriScheme: Config.NEMU_URI_SCHEME!,
    trackingId: Config.NEMU_TRACKING_ID!,
  });
}, []);
```

Com o `.env` correspondente:

```env theme={null}
NEMU_API_KEY=sua-api-key
NEMU_URI_SCHEME=seuapp
NEMU_TRACKING_ID=seu-tracking-id
```

***

## Identificação de usuários

Após o login do usuário no seu app, associe o ID dele ao dispositivo. Isso permite que a Nemu cruze dados de atribuição com o seu sistema de usuários.

### Registrar usuário

```typescript theme={null}
import { NemuTracking } from '@usenemu-account/react-native-sdk';

// Após o login bem-sucedido
function onLoginSuccess(userId: string) {
  NemuTracking.setUserId(userId);
}
```

O SDK salva o ID localmente e envia a associação ao backend automaticamente.

### Limpar usuário no logout

```typescript theme={null}
function onLogout() {
  NemuTracking.clearUserId();
}
```

> **Nota:** `clearUserId()` remove apenas a associação local. O histórico de atribuição no backend é preservado.

***

## Deep Links

O SDK processa dois tipos de deep links automaticamente:

### Deep links diretos

Ocorrem quando o **app já está instalado** e o usuário clica em um Smart Link. O sistema operacional abre o app diretamente (via Universal Link / App Link ou URI scheme).

O fluxo é transparente:

1. O usuário clica no Smart Link
2. O app abre com a URL
3. O SDK processa a URL e registra a sessão
4. Os listeners registrados via `onDeepLink` são notificados com os dados

### Deep links diferidos (Deferred Deep Links)

Ocorrem quando o **app não está instalado**. O usuário clica no Smart Link, é redirecionado para a loja, instala o app e abre pela primeira vez.

O SDK detecta automaticamente esse cenário na primeira abertura e entrega os dados de atribuição e deep link via `onDeepLink` com `isDeferred: true`.

### Listener reativo (onDeepLink)

Registre um callback para receber os dados do deep link assim que estiverem disponíveis:

```typescript theme={null}
import React, { useEffect } from 'react';
import { NemuTracking } from '@usenemu-account/react-native-sdk';
import type { DeepLinkData } from '@usenemu-account/react-native-sdk';

function App() {
  useEffect(() => {
    NemuTracking.init({
      apiKey: 'sua-api-key',
      uriScheme: 'seuapp',
      trackingId: 'seu-tracking-id',
    });

    const unsubscribe = NemuTracking.onDeepLink((data: DeepLinkData) => {
      console.log('Deep link recebido:', data);

      if (data.deepLinkValue) {
        // Navegar para a tela correspondente
        // Ex: data.deepLinkValue = "product/456"
        navigateTo(data.deepLinkValue);
      }

      if (data.utms) {
        console.log('Fonte:', data.utms.source);
        console.log('Campanha:', data.utms.campaign);
      }

      console.log('Foi diferido?', data.isDeferred);
    });

    // Limpar listener ao desmontar
    return () => unsubscribe();
  }, []);

  return (/* ... */);
}
```

> **Replay automático:** se um deep link já foi processado antes do listener ser registrado, o callback é disparado imediatamente com os dados mais recentes. Isso evita que o app perca o deep link inicial.

### Consulta imperativa (getDeepLinkData)

Se preferir consultar os dados de forma imperativa em vez de usar o listener:

```typescript theme={null}
async function checkDeepLink() {
  const data = await NemuTracking.getDeepLinkData();

  if (data) {
    console.log('App aberto via Smart Link:', data.deepLinkValue);
  } else {
    console.log('App aberto organicamente');
  }
}
```

### Estrutura do DeepLinkData

```typescript theme={null}
interface DeepLinkData {
  /** Valor do deep link (ex: "product/456", "category/shoes") */
  deepLinkValue: string | null;

  /** true = deep link diferido (usuário instalou após clicar) */
  isDeferred: boolean;

  /** Parâmetros UTM do Smart Link */
  utms: {
    source: string | null;
    medium: string | null;
    campaign: string | null;
    content: string | null;
    term: string | null;
  } | null;
}
```

***

## Atribuição

### Histórico da última sessão (last touch)

Consulte os UTMs da interação mais recente do usuário. Responde à pergunta: **"quais foram os UTMs da última visita?"**

```typescript theme={null}
async function checkLastSession() {
  const session = await NemuTracking.getLastSessionHistory();

  if (session) {
    console.log('Fonte:', session.utm_source);
    console.log('Mídia:', session.utm_medium);
    console.log('Campanha:', session.utm_campaign);
    console.log('Conteúdo:', session.utm_content);
    console.log('Termo:', session.utm_term);
  } else {
    console.log('Nenhuma sessão encontrada');
  }
}
```

### Inserção manual de histórico de UTM (`setSessionHistory`)

Use `setSessionHistory` quando você precisa registrar UTMs manualmente em fluxos personalizados (por exemplo, campanha definida pelo backend, onboarding interno ou regra de negócio que não depende de deep link).

```typescript theme={null}
NemuTracking.setSessionHistory({
  utm_source: 'newsletter',
  utm_medium: 'email',
  utm_campaign: 'black_friday_2026',
  utm_content: 'cta_header',
  utm_term: 'ofertas',
});
```

| Parâmetro      | Tipo             | Obrigatório | Descrição          |
| -------------- | ---------------- | ----------- | ------------------ |
| `utm_source`   | `string`         | Sim         | Origem da campanha |
| `utm_medium`   | `string \| null` | Não         | Mídia/canal        |
| `utm_campaign` | `string \| null` | Não         | Nome da campanha   |
| `utm_content`  | `string \| null` | Não         | Conteúdo da peça   |
| `utm_term`     | `string \| null` | Não         | Termo adicional    |

Comportamento importante:

* `utm_source` é obrigatório; chamadas inválidas são ignoradas com segurança
* O método reutiliza o fluxo interno de sessão/histórico do SDK (`trackEvent`)
* Existe desduplicação para evitar criação excessiva de históricos em chamadas repetidas
* A execução é assíncrona e resiliente (falhas internas não devem quebrar o app)

> **Quando usar:** se a origem já veio por Smart Link/deep link com UTMs válidos, prefira o fluxo automático. Use `setSessionHistory` para complementar cenários não cobertos pelo link.

### Exemplo: anexando UTMs a uma compra

```typescript theme={null}
async function trackPurchase(orderId: string, amount: number) {
  const lastSession = await NemuTracking.getLastSessionHistory();

  const purchasePayload = {
    orderId,
    amount,
    lastSource: lastSession?.utm_source ?? null,
    lastCampaign: lastSession?.utm_campaign ?? null,
    lastMedium: lastSession?.utm_medium ?? null,
    lastContent: lastSession?.utm_content ?? null,
    lastTerm: lastSession?.utm_term ?? null,
  };

  // Enviar para o seu backend
  await fetch('https://sua-api.com/purchases', {
    method: 'POST',
    body: JSON.stringify(purchasePayload),
  });
}
```

***

## Integração com WebView

Quando o app embute conteúdo web via WebView e a página precisa consumir os dados de atribuição (por exemplo, os UTMs retornados por `getLastSessionHistory`), o SDK roda apenas no lado nativo (React Native). Para que a página web tenha acesso a esses dados, você precisa criar uma **ponte bidirecional** entre o React Native e a WebView.

### Estratégia recomendada

A abordagem mais confiável combina dois mecanismos:

* **Pré-injeção**: os dados são disponibilizados como variável global na WebView antes do carregamento do conteúdo
* **Bridge sob demanda**: a página web pode solicitar uma versão atualizada do histórico a qualquer momento

> **Por que não usar query params na URL?** É a abordagem mais simples, mas tem limite de tamanho, expõe os dados na URL e não permite atualizar valores sem recarregar a página. Use apenas quando os dados são pequenos e estáticos.

### Implementação no React Native

```tsx theme={null}
import React, { useEffect, useRef, useState } from 'react';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
import { NemuTracking } from '@usenemu-account/react-native-sdk';
import type { TrackingSessionHistory } from '@usenemu-account/react-native-sdk';

function ScreenWithWebView() {
  const webRef = useRef<WebView>(null);
  const [initialHistory, setInitialHistory] =
    useState<TrackingSessionHistory | null | undefined>(undefined);

  useEffect(() => {
    NemuTracking.getLastSessionHistory().then(setInitialHistory);
  }, []);

  // Aguarda a consulta inicial antes de montar a WebView
  if (initialHistory === undefined) return null;

  const preload = `
    window.__NEMU_HISTORY__ = ${JSON.stringify(initialHistory)};
    window.nemuRequestHistory = function () {
      window.ReactNativeWebView.postMessage(
        JSON.stringify({ type: 'NEMU_GET_HISTORY' })
      );
    };
    true;
  `;

  const onMessage = async (event: WebViewMessageEvent) => {
    try {
      const msg = JSON.parse(event.nativeEvent.data);
      if (msg.type === 'NEMU_GET_HISTORY') {
        const history = await NemuTracking.getLastSessionHistory();
        webRef.current?.injectJavaScript(`
          window.dispatchEvent(new CustomEvent('nemu:history', {
            detail: ${JSON.stringify(history)}
          }));
          true;
        `);
      }
    } catch {
      // Ignora mensagens fora do protocolo
    }
  };

  return (
    <WebView
      ref={webRef}
      source={{ uri: 'https://sua-pagina.com' }}
      injectedJavaScriptBeforeContentLoaded={preload}
      onMessage={onMessage}
    />
  );
}
```

### Consumo no lado web

Dentro da página carregada na WebView, os dados ficam disponíveis logo no carregamento e podem ser atualizados sob demanda:

```js theme={null}
// Acesso imediato no carregamento
const history = window.__NEMU_HISTORY__;
console.log('UTMs da última sessão:', history);

// Receber atualizações quando o React Native responder a uma solicitação
window.addEventListener('nemu:history', (event) => {
  console.log('Histórico atualizado:', event.detail);
});

// Solicitar uma versão atualizada
window.nemuRequestHistory();
```

### Considerações importantes

* **Aguarde o `init` do SDK** antes de montar a WebView. Chamar `getLastSessionHistory()` antes de `NemuTracking.init()` faz a Promise ser rejeitada.
* **Sanitização do JSON**: ao injetar dados na WebView, sempre use `JSON.stringify`. Nunca interpole strings diretamente para evitar XSS caso algum campo venha de fonte externa.
* **`injectedJavaScriptBeforeContentLoaded`**: requer `react-native-webview` >= 11. Em versões anteriores, use `injectedJavaScript` (executa após o DOM carregar — pode haver race condition com scripts da página).
* **Detecção do ambiente**: se a mesma página web também roda fora da WebView (no navegador), trate `window.ReactNativeWebView` como opcional para evitar erros:

```js theme={null}
const isInWebView = typeof window.ReactNativeWebView !== 'undefined';

if (isInWebView) {
  window.nemuRequestHistory();
}
```

***

## Uso avançado

### Modo debug

Ative o modo debug para ver logs detalhados de todas as operações do SDK no console:

```typescript theme={null}
NemuTracking.init({
  apiKey: 'sua-api-key',
  uriScheme: 'seuapp',
  trackingId: 'seu-tracking-id',
  isDebugMode: true,
});
```

Os logs aparecerão prefixados com `[NemuSDK]` e incluem informações sobre:

* Processamento de deep links
* Fluxo de inicialização
* Erros e falhas de rede

> **Importante:** desative o modo debug em produção. Os logs podem conter informações sensíveis.

### Sobrescrita da URL base

Em ambiente de desenvolvimento ou staging, você pode apontar o SDK para uma API diferente:

```typescript theme={null}
NemuTracking.init({
  apiKey: 'sua-api-key',
  uriScheme: 'seuapp',
  trackingId: 'seu-tracking-id',
  isDebugMode: true,
  baseUrl: 'https://staging-trackings.nemu.com.br',
});
```

> A `baseUrl` só é utilizada quando `isDebugMode` é `true`. Em modo de produção, o SDK sempre usa a URL padrão.

***

## Solução de problemas

### Erro de autenticação npm ao instalar

**Erro:**

```
npm ERR! 401 Unauthorized - GET https://registry.npmjs.org/@usenemu%2freact-native-sdk
```

**Solução:**

* Verifique se o arquivo `.npmrc` existe na raiz do projeto
* Confirme que o token está correto e não expirou
* Entre em contato com o suporte da Nemu para validar ou renovar o token

***

### Erro "NemuTracking.init() must be called before using any other method"

**Causa:** um método do SDK foi chamado antes da inicialização.

**Solução:** certifique-se de que `NemuTracking.init()` é chamado no `useEffect` do componente raiz **antes** de qualquer outro método do SDK.

***

### Pod install falha no iOS

**Erro:**

```
[!] Unable to find a specification for `react-native-keychain`
```

**Solução:**

1. Verifique se `react-native-keychain` está instalado como dependência JavaScript
2. Execute:
   ```bash theme={null}
   cd ios
   pod deintegrate
   pod install
   ```

***

### Deep links não funcionam no iOS

**Verificações:**

* O Associated Domain está configurado corretamente no Xcode? (formato: `applinks:seu-dominio`)
* O arquivo `apple-app-site-association` está publicado e acessível no domínio? (configurado pela equipe da Nemu)
* O URI scheme está declarado no `Info.plist`?

***

### Deep links não funcionam no Android

**Verificações:**

* Os intent filters estão corretos no `AndroidManifest.xml`?
* O domínio está com verificação automática ativa (`android:autoVerify="true"`)?
* O arquivo `assetlinks.json` está publicado no domínio? (configurado pela equipe da Nemu)

***

### Nenhum dado de atribuição retornado

**Verificações:**

* O `apiKey` e o `trackingId` estão corretos?
* O Smart Link está configurado e ativo no painel da Nemu?
* Teste com `isDebugMode: true` e verifique os logs `[NemuSDK]` no console

***
