The Atatus Flutter SDK reports network requests as RUM resources, so you can see the URL, method, status code, and duration of every call your application makes. Each integration ships as its own package, so you add only the ones your application uses.

This page covers the four network integrations and how to choose between them.

Note: This guide covers Android targets only. iOS instrumentation is not part of these guides.

Choose an integration

Pick the package that matches the client your application uses:

Client Package How it attaches
dart:io HttpClient, and the http package on top of it atatus_tracking_http_client Globally, with enableHttpTracking()
The http package, wrapped explicitly atatus_tracking_http_client Per client, with AtatusClient
Dio atatus_dio Per client, with addAtatusInterceptor()
gRPC atatus_grpc_interceptor Per client, with AtatusGrpcInterceptor
GraphQL (gql_link) atatus_gql_link In the link chain, with AtatusGqlLink

All of them report resources on their own. To also connect those resources to your backend traces, list your API domains in firstPartyHosts. See Flutter Distributed Tracing.

Track HTTP requests

atatus_tracking_http_client tracks requests made with dart:io HttpClient. The http package uses HttpClient underneath on Android, so this one integration covers both.

Add the package to your pubspec.yaml:

copy
icon/buttons/copy
dependencies:
  atatus_flutter_plugin: ^1.0.4
  atatus_tracking_http_client: ^1.0.4

Call enableHttpTracking() on your configuration before you initialize the SDK:

copy
icon/buttons/copy
import 'package:atatus_tracking_http_client/atatus_tracking_http_client.dart';

final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
  firstPartyHosts: ['api.example.com'],
)..enableHttpTracking();

Every HttpClient created after initialization is then tracked, with no change to your request code.

Warning:

enableHttpTracking() replaces HttpOverrides.global. If your application sets its own HttpOverrides, install yours before you initialize Atatus. The SDK reads HttpOverrides.current during initialization and wraps it, so your overrides keep working. Installing yours afterwards replaces the Atatus one and stops all network tracking.

Ignore specific URLs

Pass ignoreUrlPatterns to skip requests you do not want reported, such as health checks or an endpoint already tracked by another integration:

copy
icon/buttons/copy
final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
)..enableHttpTracking(
    ignoreUrlPatterns: [
      RegExp('example.com/graphql'),
      RegExp('/health\$'),
    ],
  );

Each pattern is matched against the full request URL.

Wrap a single http client

AtatusClient is a composable http.Client you create yourself. Use it instead of enableHttpTracking() when either of these is true:

  • You use a native HTTP library such as cronet_http or cupertino_http. Those do not go through dart:io HttpClient, so global tracking cannot see them.
  • You want to track only some requests rather than all of them.

Create the client and pass it wherever you make requests:

copy
icon/buttons/copy
import 'package:atatus_tracking_http_client/atatus_tracking_http_client.dart';
import 'package:http/http.dart' as http;

final atatusClient = AtatusClient(
  atatusSdk: AtatusSdk.instance,
  innerClient: http.Client(),
);

final response = await atatusClient.get(Uri.parse('https://api.example.com/orders'));

innerClient is optional. Leave it out and AtatusClient creates a default http.Client for you. Because it wraps any http.BaseClient, you can compose it with other clients such as a retry client.

AtatusClient also accepts ignoreUrlPatterns, and an attributesProvider that lets you attach your own attributes to each resource:

copy
icon/buttons/copy
final atatusClient = AtatusClient(
  atatusSdk: AtatusSdk.instance,
  ignoreUrlPatterns: [RegExp('/health\$')],
  attributesProvider: (request, response, error) {
    return {'tenant': tenantIdFor(request)};
  },
);
Note:

Use one approach or the other. AtatusClient and enableHttpTracking() both track the same http package traffic, so using both reports each request twice. The exception is cronet_http and cupertino_http, which global tracking cannot see at all, so the two can safely run together in that case.

Track Dio requests

atatus_dio reports Dio requests as RUM resources. Add the package:

copy
icon/buttons/copy
dependencies:
  atatus_flutter_plugin: ^1.0.4
  atatus_dio: ^1.0.4

Add the interceptor to your Dio instance:

copy
icon/buttons/copy
import 'package:atatus_dio/atatus_dio.dart';
import 'package:dio/dio.dart';

final dio = Dio();

dio.addAtatusInterceptor(AtatusSdk.instance);
Note:

addAtatusInterceptor inserts the Atatus interceptor at the front of the list, so it sees every request even if a later interceptor stops the chain. Call it after the rest of your Dio setup so nothing displaces it.

Dio options

addAtatusInterceptor accepts four optional parameters:

Parameter Purpose
ignoreUrlPatterns A list of RegExp matched against the request URL. Matching requests are not reported
attributesProvider An AtatusDioAttributeProvider that adds your own attributes on request, response, and error
parentSpanResolver Returns a parent span ID for a request, so the resource is attached to a span you already have
kindResolver Returns a RumResourceType for a response, overriding the type derived from the content type

To add your own attributes, implement AtatusDioAttributeProvider:

copy
icon/buttons/copy
class TenantAttributes implements AtatusDioAttributeProvider {
  @override
  Map<String, Object?>? onRequest(RequestOptions request) =>
      {'tenant': request.headers['x-tenant']};

  @override
  Map<String, Object?>? onResponse(Response<dynamic> response) => null;

  @override
  Map<String, Object?>? onError(DioException err) => {'retryable': err.type.name};
}

dio.addAtatusInterceptor(
  AtatusSdk.instance,
  attributesProvider: TenantAttributes(),
);

Attributes returned from onRequest land on the resource when it starts. Attributes from onResponse and onError land on it when it finishes.

Track gRPC requests

atatus_grpc_interceptor reports gRPC calls as RUM resources. Add the package:

copy
icon/buttons/copy
dependencies:
  atatus_flutter_plugin: ^1.0.4
  atatus_grpc_interceptor: ^1.0.4

Create the interceptor with your channel, then pass it to your generated client:

copy
icon/buttons/copy
import 'package:atatus_grpc_interceptor/atatus_grpc_interceptor.dart';
import 'package:grpc/grpc.dart';

final channel = ClientChannel(
  'api.example.com',
  port: 50051,
);

final atatusInterceptor = AtatusGrpcInterceptor(AtatusSdk.instance, channel);

final stub = GreeterClient(channel, interceptors: [atatusInterceptor]);

The interceptor needs the channel as well as the SDK, because it builds the request URL from the channel host and port so that first party host matching works.

Each call is reported with the gRPC method path in a grpc.method attribute.

Note:

The gRPC interceptor tracks unary calls only. Streaming calls are not intercepted and do not appear as resources.

Track GraphQL requests

atatus_gql_link reports GraphQL operations as RUM resources and records the operation name, the operation type, and the variables. Add the package:

copy
icon/buttons/copy
dependencies:
  atatus_flutter_plugin: ^1.0.4
  atatus_gql_link: ^1.0.4

Add AtatusGqlLink above your terminating link:

copy
icon/buttons/copy
import 'package:atatus_gql_link/atatus_gql_link.dart';
import 'package:gql_link/gql_link.dart';
import 'package:gql_http_link/gql_http_link.dart';

const graphQlUrl = 'https://api.example.com/graphql';

final link = Link.from([
  AtatusGqlLink(AtatusSdk.instance, Uri.parse(graphQlUrl)),
  HttpLink(graphQlUrl),
]);

AtatusGqlLink is not a terminating link, so it always needs a link such as HttpLink after it.

Warning:

If you use atatus_gql_link together with atatus_tracking_http_client, tell the HTTP tracking to ignore your GraphQL endpoint. Otherwise every operation is reported twice, once by each integration, and the backend trace can break:

final configuration = AtatusConfiguration(
  licenseKey: '<LICENSE_KEY>',
  env: '<ENV_NAME>',
  appName: '<APP_NAME>',
)..enableHttpTracking(
    ignoreUrlPatterns: [RegExp('api.example.com/graphql')],
  );

What is collected from a GraphQL operation

Each operation carries these attributes in addition to the usual resource fields:

Attribute Description
_atatus.graphql.operation_name The operation name, taken from the request or read from the query document
_atatus.graphql.operation_type query, mutation, or subscription
_atatus.graphql.variables The variables sent with the operation, JSON encoded
_atatus.graphql.errors Any errors returned in the GraphQL response
Warning:

Variables are recorded as sent. If your queries carry personal data, passwords, or tokens in their variables, redact them with a resourceEventMapper before the event leaves the device. See Modify or drop RUM events.

Track a custom resource

If none of the integrations covers a request, report it yourself with startResource and stopResource. See Manually track custom resources.

Next steps