initialize method

Future<void> initialize({
  1. required int siteId,
  2. required String url,
  3. bool newVisit = true,
  4. String? visitorId,
  5. String? uid,
  6. String? contentBaseUrl,
  7. DispatchSettings dispatchSettings = const DispatchSettings.nonPersistent(),
  8. Duration? pingInterval = const Duration(seconds: 30),
  9. String? tokenAuth,
  10. LocalStorage? localStorage,
  11. PackageInfo? packageInfo,
  12. PlatformInfo? platformInfo,
  13. bool cookieless = false,
  14. Level verbosityLevel = Level.off,
  15. Map<String, String> customHeaders = const {},
  16. String? userAgent,
  17. bool attachLastScreenInfo = true,
})

Initialize the tracker.

This method must be called before any other method. Otherwise they might throw an UninitializedMatomoInstanceException.

If the tracker is already initialized, an AlreadyInitializedMatomoInstanceException will be thrown.

The newVisit parameter is used to mark this initialization the start of a new visit. If set to false it is left to Matomo to decide if this is a new visit or not. In practice, this will be used as the newVisit parameter in the first track... method call but only if the newVisit parameter in that method call is left to null.

The visitorId should have a length of 16 characters otherwise an ArgumentError will be thrown. This parameter corresponds with the _id and should not be confused with the user id uid. See the Visitor class for additional remarks. It is recommended to leave this to null to use an automatically generated id.

If cookieless is set to true, a CookielessStorage instance will be used. This means that the first_visit and the user_id will be stored in memory and will be lost when the app is closed.

The pingInterval is used to set the interval in which pings are send to Matomo to circumvent the last page viewtime issue. To deactivate pings, set this to null. The default value is a good compromise between accuracy and network traffic.

It is recommended to leave userAgent to null so it will be detected automatically.

Implementation

Future<void> initialize({
  required int siteId,
  required String url,
  bool newVisit = true,
  String? visitorId,
  String? uid,
  String? contentBaseUrl,
  DispatchSettings dispatchSettings = const DispatchSettings.nonPersistent(),
  Duration? pingInterval = const Duration(seconds: 30),
  String? tokenAuth,
  LocalStorage? localStorage,
  PackageInfo? packageInfo,
  PlatformInfo? platformInfo,
  bool cookieless = false,
  Level verbosityLevel = Level.off,
  Map<String, String> customHeaders = const {},
  String? userAgent,
  bool attachLastScreenInfo = true,
}) async {
  if (_initialized) {
    throw const AlreadyInitializedMatomoInstanceException();
  }

  if (visitorId != null && visitorId.length != 16) {
    throw ArgumentError.value(
      visitorId,
      'visitorId',
      'The visitorId must be 16 characters long',
    );
  }

  assertDurationNotNegative(
    value: dispatchSettings.dequeueInterval,
    name: 'dequeueInterval',
  );
  assertDurationNotNegative(
    value: pingInterval,
    name: 'pingInterval',
  );

  log.setLogging(level: verbosityLevel);

  this.siteId = siteId;
  _url = url;
  this.customHeaders = customHeaders;
  _pingInterval = pingInterval;
  _lock = sync.Lock();
  _platformInfo = platformInfo ?? PlatformInfo.instance;
  _cookieless = cookieless;
  _tokenAuth = tokenAuth;
  _newVisit = newVisit;
  this.attachLastScreenInfo = attachLastScreenInfo;
  _dispatchSettings = dispatchSettings;

  final effectiveLocalStorage = localStorage ?? SharedPrefsStorage();
  _localStorage = cookieless
      ? CookielessStorage(storage: effectiveLocalStorage)
      : effectiveLocalStorage;

  final onLoad = _dispatchSettings.onLoad;
  queue = _dispatchSettings.persistentQueue && onLoad != null
      ? await PersistentQueue.load(
          storage: _localStorage,
          onLoadFilter: onLoad,
        )
      : Queue();

  final localVisitorId = visitorId ?? await _getVisitorId();
  _visitor = Visitor(id: localVisitorId, uid: uid);

  // User agent
  this.userAgent = userAgent ?? await getUserAgent();

  _dispatcher = MatomoDispatcher(
    baseUrl: url,
    tokenAuth: tokenAuth,
    userAgent: this.userAgent,
    log: log,
  );

  // Screen Resolution
  final physicalSize = PlatformDispatcher.instance.views.first.physicalSize;
  screenResolution = Size(
    physicalSize.width,
    physicalSize.height,
  );

  // Initialize Session Information
  final now = clock.now().toUtc();
  DateTime firstVisit = now;
  int visitCount = 1;

  final localFirstVisit = await _localStorage.getFirstVisit();
  if (localFirstVisit != null) {
    firstVisit = localFirstVisit;
  } else {
    unawaited(_localStorage.setFirstVisit(now));

    // Save the visitorId for future visits.
    unawaited(_saveVisitorId(localVisitorId));
  }

  final localVisitorCount = await _localStorage.getVisitCount();
  visitCount += localVisitorCount;
  unawaited(_localStorage.setVisitCount(visitCount));

  session = Session(
    firstVisit: firstVisit,
    lastVisit: now,
    visitCount: visitCount,
  );

  if (contentBaseUrl != null) {
    contentBase = contentBaseUrl;
  } else if (kIsWeb) {
    contentBase = Uri.base.toString();
  } else {
    final effectivePackageInfo =
        packageInfo ?? await PackageInfo.fromPlatform();
    contentBase = 'https://${effectivePackageInfo.packageName}';
  }

  _optOut = await _localStorage.getOptOut();
  unawaited(_localStorage.setOptOut(optOut: _optOut));

  log.fine(
    'Matomo Initialized: firstVisit=$firstVisit; lastVisit=$now; visitCount=$visitCount; visitorId=$visitorId; contentBase=$contentBase; resolution=${screenResolution.width}x${screenResolution.height}; userAgent=${this.userAgent}',
  );
  _initialized = true;

  dequeueTimer = Timer.periodic(_dispatchSettings.dequeueInterval, (_) {
    _dequeue();
  });

  if (pingInterval != null) {
    pingTimer = Timer.periodic(pingInterval, (_) {
      _ping();
    });
  }

  if (queue.isNotEmpty) {
    await dispatchActions();
  }
}