Pular para o conteúdo principal

Visão geral

SDK de atribuição UTM para aplicativos Flutter. Capture UTMs recebidas por deep links e associe sessões de usuários ao rastreamento de origem em Android e iOS.

Requisitos

  • Flutter 3.29+
  • Dart 3.10+
  • Android: minSdkVersion 21
  • iOS: Deployment Target 11.0+

Instalação

1. Adicione a dependência

Para obter a biblioteca nemu_attribution, entre em contato com o suporte e receba um arquivo .zip. Após receber o .zip, extraia a pasta nemu_attribution para ./flutter/nemu_attribution (no seu projeto Flutter). No pubspec.yaml do seu projeto, adicione o pacote:
dependencies:
  nemu_attribution:
    path: ./flutter/nemu_attribution
Em seguida, instale as dependências:
flutter pub get

2. Configuração Android

No arquivo android/app/src/main/AndroidManifest.xml, adicione o intent-filter dentro da <activity> principal para habilitar deep links:
<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="https" android:host="app.seudominio.com" />
</intent-filter>

3. Configuração iOS

No Xcode, acesse Signing & Capabilities e adicione Associated Domains com o valor:
applinks:app.seudominio.com
Certifique-se de que o arquivo apple-app-site-association esteja disponível no domínio configurado.

Credenciais

O SDK precisa de duas credenciais fornecidas pela Nemu: PIXEL_ID e SDK_TOKEN.
Recomendamos utilizar variáveis de ambiente para não expor credenciais no código-fonte.
Você pode usar o pacote flutter_dotenv ou injetar via --dart-define:
flutter run \
  --dart-define=NEMU_PIXEL_ID=<SEU_PIXEL_ID> \
  --dart-define=NEMU_SDK_TOKEN=<SEU_SDK_TOKEN>
No código Dart, acesse os valores com:
const pixelId = String.fromEnvironment('NEMU_PIXEL_ID');
const sdkToken = String.fromEnvironment('NEMU_SDK_TOKEN');

Inicialização

Inicialize o SDK o mais cedo possível no ciclo de vida do app, preferencialmente na função main():
import 'package:flutter/material.dart';
import 'package:nemu_attribution/nemu_attribution.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await NemuAttribution.instance.init(
    const NemuAttributionConfig(
      pixelId: String.fromEnvironment('NEMU_PIXEL_ID'),
      sdkToken: String.fromEnvironment('NEMU_SDK_TOKEN'),
      debug: true, // Desabilite em produção
    ),
  );

  runApp(const MyApp());
}
A chamada init() é idempotente: chamar mais de uma vez não causa efeito. O SDK inicializa apenas na primeira chamada.

Identificação do Usuário

Após o login, registre o identificador único do usuário para associar a atribuição ao perfil:
import 'package:nemu_attribution/nemu_attribution.dart';

Future<void> signIn(String email, String password) async {
  final user = await authApi.login(email: email, password: password);

  await NemuAttribution.instance.setUserId(user.id);
}
Para sessões já autenticadas (ex: ao abrir o app com token salvo):
import 'package:nemu_attribution/nemu_attribution.dart';

Future<void> bootstrapSession() async {
  final user = await sessionManager.loadUser();

  if (user != null) {
    await NemuAttribution.instance.setUserId(user.id);
  }
}

Obtendo as UTMs da Sessão

Acesse as UTMs da última atribuição capturada:
import 'package:nemu_attribution/nemu_attribution.dart';

Future<void> getUtms() async {
  final attribution = await NemuAttribution.instance.getAttribution();

  print('utm_source: ${attribution?.source}');
  print('utm_medium: ${attribution?.medium}');
  print('utm_campaign: ${attribution?.campaign}');
  print('utm_content: ${attribution?.content}');
  print('utm_term: ${attribution?.term}');
}

Enviando Dados de Compra com UTMs

Ao enviar dados de compra para a API da Nemu, inclua as UTMs capturadas:
import 'package:nemu_attribution/nemu_attribution.dart';

Future<Map<String, dynamic>> buildPurchasePayload() async {
  final attribution = await NemuAttribution.instance.getAttribution();

  return {
    'transactionId': '123',
    'netValue': 99.9,
    'status': 'paid',
    'utm_source': attribution?.source,
    'utm_medium': attribution?.medium,
    'utm_campaign': attribution?.campaign,
    'utm_content': attribution?.content,
    'utm_term': attribution?.term,
  };
}

Caso precise processar uma URL manualmente (ex: recebida por outro mecanismo):
final result = await NemuAttribution.instance.captureDeepLink(
  'https://app.seudominio.com?utm_source=google&utm_medium=cpc&utm_campaign=verao',
);

if (result != null) {
  print('Atribuição capturada: ${result.source}');
}

Modo Debug

Habilite o modo debug durante o desenvolvimento para verificar a integração via logs do console:
await NemuAttribution.instance.init(
  const NemuAttributionConfig(
    pixelId: 'SEU_PIXEL_ID',
    debug: true, // Habilita logs detalhados
  ),
);
Os logs são exibidos com o prefixo [NemuAttribution] e podem ser visualizados no DevTools ou no terminal.
Desabilite o modo debug em produção.

O SDK captura automaticamente:
  • Cold-start deep links - quando o app é aberto via link (app fechado)
  • Warm-start deep links - quando o app recebe um link enquanto já está aberto
  • Deferred deep links - preserva os dados UTM mesmo quando o usuário instala o app após clicar no link
Para habilitar deferred deep links, configure o endpoint na inicialização:
await NemuAttribution.instance.init(
  const NemuAttributionConfig(
    pixelId: 'SEU_PIXEL_ID',
    sdkToken: 'SEU_SDK_TOKEN',
    deferredDeepLinkUrl: 'https://api.nemu.com.br/deferred',
  ),
);

Fluxo de Atribuição

Primeiro acesso (first install):
  1. Deep link (cold-start) -> se tiver UTMs, usa como first-touch
  2. Deferred deep link -> se configurado, tenta resolver
  3. Orgânico -> fallback (source: "organic", medium: "none")

Acessos subsequentes:
  - Deep links atualizam apenas o last-touch
  - First-touch é imutável após a primeira instalação
  - Last-touch respeita o TTL configurado (padrão: 30 dias)