snappy_snag 0.0.2 copy "snappy_snag: ^0.0.2" to clipboard
snappy_snag: ^0.0.2 copied to clipboard

An easy-to-use in-app bug reporting and user feedback SDK for Flutter, allowing users to send screenshots, device info, and custom logs seamlessly.

SnappySnag SDK #

SnappySnag is a visual bug reporting and AI auto-fix suggestion tool for Flutter applications. With a single shake or a tap of a button, developers and QA teams can capture screenshots, dump widget tree layouts, and get instant, detailed AI-powered code fix suggestions on their dashboard.

Features #

  • πŸ“Έ Prioritized Instant Screenshots: Captured immediately on-press to freeze the screen state, even during fast page transitions.
  • πŸ“ Multi-Point Pin Annotations: Tap anywhere on the captured screen to drop numbered pins (1–5) and attach itemized feedback/bug details for each specific area.
  • 🎨 Clean & Annotated Screenshot Preservation: Pin coordinates are stored as normalized vectors, keeping the original screenshot crystal clear without destructive image stamping.
  • 🌳 Widget Tree Dumper: Automatically dumps the widget hierarchy (up to a depth of 10 levels) for precise widget mapping.
  • πŸ€– AI Auto-Fix suggestions: Generates human-focused technical guides and cursor-compatible agent prompts.
  • πŸ’¬ Interactive AI Discussion & Version Sync: Directly ask follow-up questions to Gemini about architecture, alternative fixes, or trade-offs. Seamlessly sync discussion consensus into refined Version 2/3 technical guides and agent prompts with syntax-highlighted code snippets.
  • πŸ’Ύ Offline Draft & Resilience: Automatically saves drawing annotations, pins, and comments locally on connection failure or accidental dismissal. Seamlessly resume or discard drafts on the next capture without wasting user efforts.
  • ⚑ Pre-Validation Error Guard: Instantly validates API key configuration and bundle identifiers before users spend time drawing or writing, preventing post-submit authentication surprises.
  • πŸ‘₯ One-Build Role-Based Sharing: Show internal tickets and duplicate warnings to developers while keeping external clients on a clean, simple feedback flow in the exact same build.
  • πŸ›‘οΈ Package Name Lock: Prevents unauthorized API requests by locking your API Key to your registered bundle identifier.
  • 🚫 Store Production Safe: Easily disable the overlay button and sensor listeners completely in App Store/Google Play builds using the enabled configuration.

Getting started #

Add snappy_snag to your Flutter project's dependencies:

flutter pub add snappy_snag

Usage #

1. Initialize and Wrap MaterialApp #

Configure the SDK in your main.dart. We highly recommend using bool.fromEnvironment to enable SnappySnag only during internal testing (e.g., TestFlight or Google Play Internal Testing) and disabling it completely for App Store/Google Play production builds.

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:snappy_snag/snappy_snag.dart';

void main() {
  // 1. Initialize the SDK
  SnappySnag().initialize(
    apiKey: 'snag_live_your_api_key_here',
    // packageName: 'your.package.name', // Optional: Lock API key usage to your app's bundle ID
    // Optional: Identify user/tester to automatically unlock developer tickets for team members
    user: const SnappySnagUser(
      email: 'developer@example.com',
    ),
    // Optional: Enable detailed console debug logs during development (defaults to false)
    // enableLogging: kDebugMode,
    // Safely enable SnappySnag only when ENABLE_SNAPPY_SNAG=true is passed at build time.
    // It will automatically bypass overlay rendering and sensor listeners in production builds.
    enabled: const bool.fromEnvironment('ENABLE_SNAPPY_SNAG', defaultValue: false) || kDebugMode,
  );

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // 2. Simply pass SnappySnag's defaultNavigatorKey
      navigatorKey: SnappySnag.defaultNavigatorKey,
      // 3. Wrap your screen with SnappySnagOverlay in builder
      builder: (context, child) => SnappySnagOverlay(
        child: child ?? const SizedBox.shrink(),
      ),
      home: const MyHomePage(),
    );
  }
}

πŸ’‘ Tip: Dynamic User Info: If users log in after app startup, call SnappySnag().setUser(SnappySnagUser(id: user.id, email: user.email)) anywhere in your authentication flow. Call SnappySnag().clearUser() on logout.

2. Trigger Button Visibility & Control #

By default, the floating capture button is hidden across all modes (showTriggerButton: false) to keep your application's UI completely undisturbed.

You can display or control the trigger button as needed:

  • Enable Floating Button for Rapid Testing: Pass showTriggerButton: true in initialize() to display the floating overlay button immediately:

    SnappySnag().initialize(
      apiKey: '...',
      showTriggerButton: true, // Display floating button immediately
    );
    
  • Hide on Specific Screens (Declarative): Wrap any screen (e.g. camera, video player, payment screen) with SnappySnagHideButton:

    class CameraScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return SnappySnagHideButton(
          child: Scaffold(
            body: YourCameraView(),
          ),
        );
      }
    }
    
  • Programmatic Visibility Control:

    SnappySnag().showTriggerButton();
    SnappySnag().hideTriggerButton();
    SnappySnag().setTriggerButtonVisibility(true);
    

3. Widget Tree Hierarchy & Privacy Opt-Out (enableWidgetTree) #

By default (enableWidgetTree: true), SnappySnag extracts the Flutter UI hierarchy (up to 10 levels deep) to give Gemini AI complete context on nested layouts and styling:

  • Automatic On-Device PII Redaction:
    • Text fields, passwords, and user input widgets are automatically redacted before sending.
    • Long text labels (> 15 characters) are truncated.
  • Complete Hierarchy Opt-Out for Strict Compliance: If your application operates under strict security or regulatory compliance (e.g. healthcare, banking) where sending UI component structures is restricted, you can completely opt out:
    SnappySnag().initialize(
      apiKey: '...',
      enableWidgetTree: false, // Disables widget tree traversal completely
    );
    

    πŸ’‘ When enableWidgetTree: false, SnappySnag skips tree traversal entirely and relies strictly on screenshot visual cues and user annotations for AI analysis. The dashboard will automatically reflect this as Visual Screenshot Analysis (UI Tree Excluded).

4. Logging & Console Output (enableLogging) #

By default, SnappySnag suppresses all debug output (enableLogging: false) to keep your host app's debug and release console output completely clean.

To enable detailed console logs for debugging during development:

SnappySnag().initialize(
  apiKey: '...',
  enableLogging: kDebugMode, // Only enable detailed debug logs in debug mode
);

⚠️ Security & Privacy Note: Disable logging (enableLogging: false) before releasing your application to production. Debug logs may contain sensitive operational details, including screen class names, UI widget attributes, and reporter user metadata.

Note: Critical configuration errors (such as missing apiKey, security guard dev-mode fallbacks, and macOS sandbox permission guides) will always be output regardless of enableLogging.

5. Multi-Point Pin Drop & Itemized Feedback #

When users capture a screenshot, they can annotate specific UI elements with numbered pins (1–5) and write separate notes for each pin:

  • Drop Pins: Tap anywhere on the captured screenshot to place a pin marker.
  • Itemized Notes: Add targeted feedback or repro notes per pin, helping developers address multiple UI issues in a single report without confusing clutter.
  • Non-Destructive Vectors: Pin coordinates (x, y percentages) are stored separately from the image. The original screenshot remains intact and clean on your dashboard.

6. Launch Feedback Mode Manually (e.g. from Settings or In-App Menu) #

When the floating button is hidden (via showTriggerButton: false or SnappySnagHideButton), or if you prefer triggering feedback through your own custom UI (such as a "Report Bug" button in a Settings or Help drawer), call SnappySnag.startFeedbackMode:

ListTile(
  leading: const Icon(Icons.feedback_outlined),
  title: const Text('Report a Bug / Feedback'),
  onTap: () {
    // Starts Feedback Mode with a guidance banner and temporary capture trigger
    SnappySnag.startFeedbackMode(context: context);
  },
)

πŸ’‘ When invoked, it displays a guided prompt modal and temporarily reveals the capture button, allowing the user to navigate anywhere in the app to capture and highlight the issue.

7. Build for TestFlight / Internal Testing #

To compile your app with SnappySnag enabled, build with the --dart-define flag:

flutter build ipa --dart-define=ENABLE_SNAPPY_SNAG=true
flutter build appbundle --dart-define=ENABLE_SNAPPY_SNAG=true

8. Build for App Store / Google Play Store (Production) #

To compile your app for production release, build normally. SnappySnag will automatically be disabled, will not render the overlay button, and will not register any shake listeners:

flutter build ipa

Smart Role-Based Access & Multi-Layer Safety Guards #

In team and client work, building separate app binaries (one for internal developers and one for external clients) is time-consuming and prone to human error. SnappySnag provides a comprehensive defense and access control system to safely share a single build between developers and clients without risking internal leakages.

1. One-Build Sharing: Role-Based Developer In-App Features #

With mode: SnappySnagMode.dev, you can let your development team view existing internal tickets and duplicate warnings, while ensuring clients and external testers only see a clean, distraction-free feedback submission screen.

πŸ”’ Default Safety Note: Newly created projects default to Disabled for developer tickets. You can switch this to Allowed Only or Everyone anytime in your dashboard. Furthermore, if the SDK is running with mode: SnappySnagMode.user, developer tickets are always strictly hidden, irrespective of dashboard settings.

Control access effortlessly from your Web Dashboard > Project Settings > General & SDK:

  • πŸ›‘ Disabled (Default): Suppresses developer tickets completely across all client devices.
  • πŸ‘₯ Allowed Only (Recommended for Teams):
    • Team Members: Owners and developers registered in your dashboard's "Team & Members" automatically get full access to internal tickets when their reporterEmail matches.
    • Additional Allowed Emails: Seamlessly whitelist client leads or external QA testers by email address without touching your code or re-deploying.
    • Unauthenticated / Unknown Testers: Automatically skip internal tickets and transition directly to the feedback submission screen.
  • 🌐 Everyone (Passcode Protected):
    • In projects set to "Everyone", internal tickets and duplicate warnings are protected by a 4-digit Dev Features Passcode auto-generated on your Web Dashboard.
    • When opening the internal tickets modal ("ε…¨ζŒ‡ζ‘˜δΈ€θ¦§"), users are prompted to enter this 4-digit passcode.
    • Zero Storage Leakage: The entered passcode is kept strictly in volatile memory only during the current app session and is never saved to persistent local storage (e.g. SharedPreferences). If the app process terminates or is killed, the passcode is completely forgotten.
    • Real-Time Revocation & Re-Authentication: If your dashboard administrator regenerates the passcode or updates project settings, the active app session automatically verifies the passcode on the next ticket view attempt. The invalid passcode is instantly purged from memory, and the user is immediately prompted with the passcode modal to enter the updated passcode.

2. Automatic Release Guard (kReleaseMode) #

When you build your application in Release Mode (flutter build ipa / flutter build appbundle), SnappySnag automatically checks Flutter's kReleaseMode. Even if mode: SnappySnagMode.dev was inadvertently left configured in your source code, SnappySnag automatically falls back to SnappySnagMode.user, completely hiding developer tickets.

πŸ’‘ Internal Dogfooding in Release Builds: If you intentionally wish to test developer mode in a release-compiled build (e.g. TestFlight distribution to internal team members), explicitly set forceDevInRelease: true:

SnappySnag().initialize(
  apiKey: 'YOUR_KEY',
  packageName: 'com.example.app',
  mode: SnappySnagMode.dev,
  forceDevInRelease: const bool.fromEnvironment('FORCE_DEV_MODE', defaultValue: false),
);

3. Client & Server Rate Limiting (Spam & Flood Protection) #

Applies to both user and dev modes out of the box:

  • Client-Side: The send button enforces a mandatory 3-second cooldown between successive submissions to prevent accidental or malicious double-taps.
  • Server-Side: The backend API limits continuous messages to a maximum of 5 messages per minute per user/device. Exceeding requests automatically receive 429 Too Many Requests with an in-app notice.

4. Zero-Friction Pre-Validation & Offline Draft Protection #

  • Instant Pre-Validation: When the capture button is triggered, SnappySnag performs a lightweight authorization check in the background. If an invalid API key or package name mismatch (401/403) occurs, it immediately halts and alerts you without letting the user waste time annotating or typing a memo.
  • On-Device Offline Draft (Zero-Loss Resilience):
    • If a feedback submission fails due to an unstable internet connection or if the user cancels with unsaved edits, SnappySnag offers to save the current progress as a draft.
    • Privacy & Storage Safe: Drafts are stored strictly on the device's local sandbox (SharedPreferences). No draft data is sent to external servers until explicitly submitted. Only 1 active draft is retained, ensuring zero unnecessary storage overhead.
    • On the next capture attempt, users are prompted to either Resume Draft or Discard & Start New Capture.

5. Local Storage (SharedPreferences) Transparency #

SnappySnag values user privacy and transparency. The SDK uses on-device local storage (SharedPreferences) exclusively for the following two purposes:

  1. snappy_snag_device_id: A randomly generated anonymous UUID used exclusively for backend spam and rate-limit enforcement (429 Too Many Requests). Contains no personal identity or hardware fingerprints.
  2. snappy_snag_draft_v1: Temporary offline draft data (at most 1 active draft) saved strictly when the user chooses to retain unsaved edits after a failed submission or cancellation. Cleared immediately upon submission or explicit discard.

πŸ›‘οΈ Note on Passcodes & Auth: Dev Features Passcodes and authentication tokens are never written to local persistent storage. They are retained strictly in volatile app memory for the current running session only.

0
likes
160
points
95
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

An easy-to-use in-app bug reporting and user feedback SDK for Flutter, allowing users to send screenshots, device info, and custom logs seamlessly.

Homepage
Repository (GitHub)
View/report issues

Topics

#bug-reporting #feedback #developer-tools #flutter #screenshot

License

MIT (license)

Dependencies

flutter, http, screenshot, sensors_plus, shared_preferences

More

Packages that depend on snappy_snag