Pulse is a bug reporting and in-app feedback tool that allows developers to collect detailed user feedback and crash reports to improve their mobile apps. We offer a free tier for non-commerical usage, with paid plans starting at $50 per month, with pricing varying based on features and usage.

Register your backend

Create a free account on the Pulse Admin Portal and register your defect tracking and storage configurations.

Register your defect tracking system

We support sending defect reports to

  • GitHub projects via Issues
  • Atlassian JIRA
  • Slack
  • Azure Devops

Custom development can be provided if your system is not listed here, please drop us a note.

Register your attachment storage preferences

Your data is never stored, we only use our backend to safely proxy the report backs to your system of choice. However some defect traking systems, such as Atlassian JIRA do not allow API uploading of attachments, and we need to upload those attachements to some storage repo. We provide you with our own built-in storage, or you may configure your own Google Drive or AWS S3 bucket instead.

Instrumenting your code

Add the following imports to your app :

    import 'package:pulse_sdk_flutter/pulse.dart';
    import 'package:flutter_localizations/flutter_localizations.dart';
    import 'package:pulse_sdk_flutter/l10n/app_localizations.dart';

You need to set up the Global key for accessing the navigator and its context used to generate screenshots and dialogs. Pass this to your MaterialApp's navigatorKey parameter:


   MaterialApp(
     navigatorKey: pulse.navigatorKey,
     ...
   )

Add this to the startup code of your Flutter application :

    pulse = Pulse("client_id","client_secret");
    await pulse.init();

And at some point pass your BuildContext through to the package :

    pulse.setContext(context); 

Be sure to initialise the localisations :

Widget build(BuildContext context) {
return MaterialApp(
    localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
    ],
    supportedLocales: AppLocalizations.supportedLocales,
    title: 'Flutter Demo',

Customizing the Theme

The Pulse SDK supports comprehensive theme customization to match your app's design system. You can customize colors, text styles, icons, dialog appearance, and more.

Quick Start

Create a PulseTheme instance and pass it to the Pulse constructor:

import 'package:pulse_sdk_flutter/pulse.dart';

final customTheme = PulseTheme(
  dialogBorderRadius: 20.0,
  dialogBackgroundColor: Colors.white,
  primaryColor: Colors.blue,
  titleTextColor: Colors.blue,
  contentTextColor: Colors.black87,
  dialogContentPadding: EdgeInsets.all(16.0),
  titleTextStyle: TextStyle(
    fontSize: 20,
    fontWeight: FontWeight.bold,
  ),
  iconSize: 28.0,
  defectIconColor: Colors.orange,
  suggestionIconColor: Colors.green,
);

final pulse = Pulse(
  "your-client-id",
  "your-client-secret",
  theme: customTheme,
);

Available Theme Properties

You can customize the following properties:

Dialog Appearance:

  • dialogBorderRadius - Border radius for all dialogs (default: 10.0)
  • dialogBackgroundColor - Background color for dialogs
  • dialogContentPadding - Padding for dialog content (default: EdgeInsets.all(8.0))
  • dialogBlurSigmaX / dialogBlurSigmaY - Blur effects for dialog backdrop
  • dialogBarrierColor - Overlay color behind dialogs

Colors:

  • primaryColor - Primary color for icons and accents
  • titleTextColor - Text color for dialog titles
  • contentTextColor - Text color for dialog content
  • errorIconColor - Color for error icons
  • defectIconColor - Color for defect/bug report icons
  • suggestionIconColor - Color for suggestion/improvement icons
  • categoryIconColor - Color for category selection icons

Text Styles:

  • titleTextStyle - Text style for dialog titles
  • contentTextStyle - Text style for dialog content
  • buttonTextStyle - Text style for buttons

Icons:

  • iconSize - Size for all icons in dialogs

Example: Dark Theme

final darkTheme = PulseTheme(
  dialogBorderRadius: 12.0,
  dialogBackgroundColor: Color(0xFF2C2C2C),
  primaryColor: Color(0xFF64B5F6),
  titleTextColor: Colors.white,
  contentTextColor: Color(0xFFE0E0E0),
  dialogContentPadding: EdgeInsets.all(20.0),
  titleTextStyle: TextStyle(
    fontSize: 22,
    fontWeight: FontWeight.bold,
    color: Colors.white,
  ),
  contentTextStyle: TextStyle(
    fontSize: 16,
    color: Color(0xFFE0E0E0),
  ),
  iconSize: 32.0,
  errorIconColor: Color(0xFFEF5350),
  defectIconColor: Color(0xFFFF9800),
  suggestionIconColor: Color(0xFF66BB6A),
);

final pulse = Pulse(
  "client-id",
  "client-secret",
  theme: darkTheme,
);

Using Default Theme

If you don't specify a theme, the SDK will use the default Material Design theme:

final pulse = Pulse(
  "client-id",
  "client-secret",
  // No theme parameter - uses default theme
);

Modifying Existing Themes

You can create variations using the copyWith method:

final baseTheme = PulseTheme(
  dialogBorderRadius: 16.0,
  primaryColor: Colors.blue,
);

final modifiedTheme = baseTheme.copyWith(
  primaryColor: Colors.green,
  titleTextColor: Colors.green,
);

For more detailed examples and a complete reference of all theme properties, see THEMING.md and the themed example app.