influto 1.0.0 copy "influto: ^1.0.0" to clipboard
influto: ^1.0.0 copied to clipboard

Track influencer referrals, attribution, and store-direct purchase validation in your Flutter app. Mirrors the InfluTo React Native SDK.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:influto/influto.dart';
import 'package:influto_iap/influto_iap.dart';

import 'purchase_manager.dart';
import 'referral_field.dart';
import 'sample_backend.dart';

/// The full InfluTo Flutter flow, top to bottom — a copy-paste reference:
/// 1 configure → 2 attribution → 3 referral input → 4 paywall (in_app_purchase
/// → reportPurchase) → 5 confirm it landed in InfluTo.
///
/// API key defaults from --dart-define=INFLUTO_API_KEY (never committed) but is
/// editable at runtime; defaults to the harmless `it_TEST_KEY` (backend rejects).
const _defaultApiKey =
    String.fromEnvironment('INFLUTO_API_KEY', defaultValue: 'it_TEST_KEY');
const _baseUrl = 'https://influ.to/api';

void main() => runApp(const InfluToSampleApp());

class InfluToSampleApp extends StatelessWidget {
  const InfluToSampleApp({super.key});

  @override
  Widget build(BuildContext context) =>
      const MaterialApp(title: 'InfluTo Sample', home: SampleScreen());
}

class SampleScreen extends StatefulWidget {
  const SampleScreen({super.key});

  @override
  State<SampleScreen> createState() => _SampleScreenState();
}

class _SampleScreenState extends State<SampleScreen> {
  final _apiKey = TextEditingController(text: _defaultApiKey);
  final _productId = TextEditingController(text: 'to.influ.sample.pro.monthly');
  final _appUserId = TextEditingController(text: 'sample-flutter');

  bool _initialized = false;
  String _status = 'Not initialized';
  String _attribution = '—';
  String? _appliedCode;
  String _result = '';
  String _landed = '';
  String _autoSync = '';
  PurchaseManager? _purchases;
  InfluToPurchaseObserver? _observer;

  Future<void> _initialize() async {
    try {
      await InfluTo.instance.initialize(InfluToConfig(
        apiKey: _apiKey.text,
        debug: true,
        apiUrl: _baseUrl,
        appVersion: 'sample-flutter-1.0',
      ));
      await InfluTo.instance.identifyUser(_appUserId.text);
      final a = await InfluTo.instance.checkAttribution();
      final code = await InfluTo.instance.getReferralCode();
      _purchases = PurchaseManager(
        appUserId: () => _appUserId.text,
        referralCode: () => _appliedCode,
        onResult: (s) => setState(() => _result = s),
      );
      await _purchases!.start();
      if (!mounted) return;
      setState(() {
        _initialized = true;
        _status = '✅ Initialized as ${_appUserId.text}';
        _attribution = a.attributed
            ? 'Attributed → ${a.referralCode}'
            : 'Organic (no attribution link)';
        _appliedCode = code;
      });
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _initialized = false;
        _status = '❌ Init failed: $e';
      });
    }
  }

  // Opt-in auto-capture (via the influto_iap companion): listen to in_app_purchase +
  // back-sync existing purchases. Alternative to wiring reportPurchase yourself.
  Future<void> _enableAutoCapture() async {
    _observer ??= InfluToPurchaseObserver(debug: true);
    final r = await _observer!.enable();
    if (!mounted) return;
    setState(() =>
        _autoSync = 'fetched=${r.fetched} · sent=${r.sent} · failed=${r.failed}');
  }

  Future<void> _checkLanded() async {
    final s = await SampleBackend.recentConversionsSummary(
      baseUrl: _baseUrl, apiKey: _apiKey.text, appUserId: _appUserId.text,
    );
    if (!mounted) return;
    setState(() => _landed = s);
  }

  @override
  void dispose() {
    _observer?.dispose();
    _purchases?.dispose();
    _apiKey.dispose();
    _productId.dispose();
    _appUserId.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('InfluTo Sample')),
      body: ListView(padding: const EdgeInsets.all(16), children: [
        const _Title('1 · Configuration'),
        TextField(controller: _apiKey, decoration: const InputDecoration(labelText: 'InfluTo API key')),
        TextField(controller: _productId, decoration: const InputDecoration(labelText: 'Product ID (SKU)')),
        TextField(controller: _appUserId, decoration: const InputDecoration(labelText: 'App user ID')),
        const SizedBox(height: 8),
        ElevatedButton(onPressed: _initialize, child: Text(_initialized ? 'Re-initialize' : 'Initialize SDK')),
        Text(_status),
        if (_initialized) ...[
          const _Title('2 · Attribution'),
          Text('Attribution: $_attribution'),
          if (_appliedCode != null) Text('Stored code: $_appliedCode'),
          const _Title('3 · Referral code (test attribution)'),
          const Text('A · Prebuilt SDK component', style: TextStyle(fontSize: 12, color: Colors.grey)),
          ReferralCodeInput(
            appUserId: _appUserId.text,
            onApplied: (_) async {
              final c = await InfluTo.instance.getReferralCode();
              if (mounted) setState(() => _appliedCode = c);
            },
          ),
          const Divider(),
          const Text('B · Custom (build your own UI)', style: TextStyle(fontSize: 12, color: Colors.grey)),
          ReferralCodeField(
            appUserId: _appUserId.text,
            onApplied: (c) => setState(() => _appliedCode = c),
          ),
          const _Title('4 · Paywall'),
          const Text('Buys via in_app_purchase, then calls reportPurchase with the store proof.'),
          ElevatedButton(
            onPressed: () => _purchases?.buy(_productId.text),
            child: Text('Buy ${_productId.text}'),
          ),
          const _Title('5 · Result'),
          if (_result.isNotEmpty) Text(_result),
          ElevatedButton(onPressed: _checkLanded, child: const Text('Did it land in InfluTo?')),
          if (_landed.isNotEmpty) Text(_landed),
          const _Title('6 · Auto-capture (default)'),
          const Text('On store-direct apps, adding the influto_iap package makes the SDK '
              'auto-report purchases (no manual reportPurchase). Enable the observer once; it '
              'self-gates on store-direct. This runs it + a back-sync.'),
          ElevatedButton(
            onPressed: _enableAutoCapture,
            child: const Text('Enable auto-capture + back-sync'),
          ),
          if (_autoSync.isNotEmpty) Text(_autoSync),
        ],
        const SizedBox(height: 24),
      ]),
    );
  }
}

class _Title extends StatelessWidget {
  const _Title(this.text);
  final String text;

  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.only(top: 16, bottom: 4),
        child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold)),
      );
}
0
likes
160
points
75
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Track influencer referrals, attribution, and store-direct purchase validation in your Flutter app. Mirrors the InfluTo React Native SDK.

Homepage
Repository (GitHub)
View/report issues

Topics

#attribution #affiliate #influencer #referral #revenuecat

License

MIT (license)

Dependencies

flutter, http, shared_preferences

More

Packages that depend on influto