{"id":29418529,"url":"https://github.com/venhdev/dio_curl_interceptor","last_synced_at":"2026-05-16T22:05:47.763Z","repository":{"id":291900176,"uuid":"979131736","full_name":"venhdev/dio_curl_interceptor","owner":"venhdev","description":"A Flutter package providing a Dio interceptor that logs HTTP requests as cURL commands—perfect for debugging, sharing, and reproducing requests. Includes a modern Flutter UI for viewing, filtering, exporting, and managing cached cURL logs","archived":false,"fork":false,"pushed_at":"2025-10-23T16:24:07.000Z","size":1726,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-10T16:32:32.939Z","etag":null,"topics":["ansi","curl","dio","logging"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/dio_curl_interceptor","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/venhdev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-07T03:37:48.000Z","updated_at":"2026-04-29T06:52:37.000Z","dependencies_parsed_at":"2025-05-30T13:00:07.690Z","dependency_job_id":"9cb964c6-dc37-4c4a-9ded-c31b3c72ee43","html_url":"https://github.com/venhdev/dio_curl_interceptor","commit_stats":null,"previous_names":["venhdev/dio_curl_interceptor"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/venhdev/dio_curl_interceptor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venhdev%2Fdio_curl_interceptor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venhdev%2Fdio_curl_interceptor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venhdev%2Fdio_curl_interceptor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venhdev%2Fdio_curl_interceptor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/venhdev","download_url":"https://codeload.github.com/venhdev/dio_curl_interceptor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/venhdev%2Fdio_curl_interceptor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33120451,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T18:38:32.183Z","status":"ssl_error","status_checked_at":"2026-05-16T18:38:29.903Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansi","curl","dio","logging"],"created_at":"2025-07-12T00:00:23.357Z","updated_at":"2026-05-16T22:05:47.750Z","avatar_url":"https://github.com/venhdev.png","language":"Dart","funding_links":["https://www.buymeacoffee.com/venhdev"],"categories":[],"sub_categories":[],"readme":"# dio_curl_interceptor\n\n[![pub package](https://img.shields.io/pub/v/dio_curl_interceptor.svg)](https://pub.dev/packages/dio_curl_interceptor)\n[![pub points](https://img.shields.io/pub/points/dio_curl_interceptor?logo=dart)](https://pub.dev/packages/dio_curl_interceptor/score)\n[![popularity](https://img.shields.io/pub/popularity/dio_curl_interceptor?logo=dart)](https://pub.dev/packages/dio_curl_interceptor/score)\n\nA Flutter package with a Dio interceptor that logs HTTP requests as cURL—ideal for debugging. Includes a modern UI to view, filter, and manage logs, plus webhook integration for team collaboration.\n\n## Features\n\n- 🔍 Converts Dio HTTP requests to cURL commands for easy debugging and sharing.\n- 📁 Enhanced FormData handling with detailed file information in cURL commands.\n- 💾 Caches cURL commands and responses with filtering and search options.\n- 🖥️ Modern Flutter widget for viewing and managing cURL logs (search, filter by status/date, clear, copy, etc).\n- 🔔 Webhook integration for remote logging and team collaboration (Discord \u0026 Telegram support, including bug and exception reporting).\n- 🛑 Path filtering to stop specific API calls and return custom responses.\n- ⚡ Real-time filter editing with test functionality directly in the CurlViewer UI.\n- 📝 Utility methods for custom interceptors and direct use.\n\nFor detailed screenshots of the interceptor's behavior, including simultaneous and chronological logging, please refer to the [Screenshots](#screenshots) section at the bottom of this README.\n\n## Migration Guide\n\nFor detailed migration instructions, breaking changes, and code examples, please see our comprehensive [MIGRATION.md](MIGRATION.md) guide.\n\n## Terminal Compatibility\n\nBelow is a compatibility table for different terminals and their support for printing and ANSI colors:\n\n| Terminal/Console      | print | debugPrint | log (dart:developer) | ANSI Colors Support |\n| --------------------- | :---: | :--------: | :------------------: | :-----------------: |\n| VS Code Debug Console |   ✅  |     ✅     |          ✅          |         ✅          |\n| IntelliJ IDEA Console |   ❌  |     ❌     |          ❌          |         ❌          |\n\n## Usage\n\n### Option 1: Using the CurlInterceptor\n\nSimple add the interceptor to your Dio instance, all done for you:\n\n```dart\nfinal dio = Dio();\ndio.interceptors.add(CurlInterceptor()); // Simple usage with default options\n// or\ndio.interceptors.add(CurlInterceptor.allEnabled()); // Enable all options\n```\n\nYou can customize the interceptor with `CurlOptions` and `CacheOptions`:\n\n```dart\ndio.interceptors.add(CurlInterceptor(\n  curlOptions: CurlOptions(\n    status: true, // Show status codes + name in logs\n    responseTime: true, // Show response timing\n    behavior: CurlBehavior.chronological,\n    onRequest: RequestDetails(\n      visible: true,\n      ansi: Ansi.yellow, // ANSI color for request\n    ),\n    onResponse: ResponseDetails(\n      visible: true,\n      requestHeaders: true, // Show request headers\n      requestBody: true, // Show request body\n      responseBody: true, // Show response body\n      responseHeaders: true, // Show response headers\n      limitResponseBody: null, // Limit response body length (characters), default is null (no limit)\n      ansi: Ansi.green, // ANSI color for response\n    ),\n    onError: ErrorDetails(\n      visible: true,\n      requestHeaders: true,\n      requestBody: true,\n      responseBody: true,\n      responseHeaders: true,\n      limitResponseBody: null,\n      ansi: Ansi.red, // ANSI color for errors\n    ),\n    // Configure pretty printing options\n    prettyConfig: PrettyConfig(\n      blockEnabled: true, // Enable pretty printing\n      colorEnabled: true, // Force enable/disable colored\n      emojiEnabled: true, // Enable/disable emoji\n      lineLength: 100, // Set the length of separator lines\n    ),\n    // Custom printer function to override default logging behavior\n    printer: (String text) {\n      // do whatever you want with the text\n      // ...\n      // Your custom logging implementation\n      print('Custom log: $text'); // remember to print the text\n    },\n  ),\n  webhookInspectors: [\n    DiscordInspector(\n      webhookUrls: ['https://discord.com/api/webhooks/your-webhook-url'],\n      inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n      includeUrls: const ['/api/v1/users', 'https://example.com/data'],\n      excludeUrls: const ['/api/v1/auth/login', 'https://example.com/sensitive'],\n    ),\n    TelegramInspector(\n      botToken: 'YOUR_BOT_TOKEN', // Get from @BotFather\n      chatIds: [-1003019608685], // Get from getUpdates API\n      inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n      includeUrls: const ['/api/v1/users', 'https://example.com/data'],\n      excludeUrls: const ['/api/v1/auth/login', 'https://example.com/sensitive'],\n    ),\n  ],\n))\n```\n\n### Option 2: Using CurlUtils directly in your own interceptor\n\nIf you prefer to use the utility methods in your own custom interceptor, you can use `CurlUtils` directly:\n\n```dart\nclass YourInterceptor extends Interceptor {\n  // Initialize webhook inspectors\n  final webhookInspectors = [\n    DiscordInspector(\n      webhookUrls: ['https://discord.com/api/webhooks/your-webhook-url'],\n      inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n    ),\n    TelegramInspector(\n      botToken: 'YOUR_BOT_TOKEN', // Get from @BotFather\n      chatIds: [-1003019608685], // Get from getUpdates API\n      inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n    ),\n  ];\n\n  @override\n  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {\n    // ... your request handling logic (like adding headers, modifying options, etc.)\n\n    // for measure request time, it will add `X-Client-Time` header, then consume on response (error)\n    CurlUtils.addXClientTime(options);\n\n    CurlUtils.handleOnRequest(options);\n    handler.next(options);\n  }\n\n  @override\n  void onResponse(Response response, ResponseInterceptorHandler handler) {\n    // ... your response handling logic\n    CurlUtils.handleOnResponse(response, webhookInspectors: webhookInspectors);\n    handler.next(response);\n  }\n\n  @override\n  void onError(DioException err, ErrorInterceptorHandler handler) {\n    // ... your error handling logic\n    CurlUtils.handleOnError(err, webhookInspectors: webhookInspectors);\n    handler.next(err);\n  }\n}\n```\n\n#### Using Multiple Webhook Inspectors\n\nYou can configure multiple webhook inspectors to send notifications to different services simultaneously. Each inspector operates independently with its own filters and configuration:\n\n```dart\n// Example of using multiple webhook inspectors\nfinal webhookInspectors = [\n  DiscordInspector(\n    webhookUrls: ['https://discord.com/api/webhooks/your-discord-webhook'],\n    inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n    includeUrls: ['api.example.com'],\n  ),\n  TelegramInspector(\n    botToken: 'YOUR_BOT_TOKEN', // Get from @BotFather\n    chatIds: [-1003019608685], // Get from getUpdates API\n    inspectionStatus: [ResponseStatus.serverError], // Only server errors to Telegram\n    includeUrls: ['api.example.com'],\n  ),\n];\n\n// Use with CurlInterceptor\ndio.interceptors.add(CurlInterceptor(\n  webhookInspectors: webhookInspectors,\n  // ... other options\n));\n```\n\n### Option 3: Using path filtering\n\nYou can use path filtering to stop specific API calls and return custom responses:\n\n```dart\nfinal dio = Dio();\n\n// Create filter options\nfinal filterOptions = FilterOptions(\n  rules: [\n    // Block access to a specific endpoint\n    FilterRule.exact('/api/sensitive-data'),\n    \n    // Mock a response for a specific endpoint\n    FilterRule.exact(\n      '/api/users/profile',\n      responseData: {\n        'id': 'mock-user-123',\n        'name': 'Mock User',\n        'email': 'mock@example.com',\n      },\n    ),\n    \n    // Use regex pattern to match multiple endpoints\n    FilterRule.regex(\n      r'/api/v1/.*',\n      responseData: {'message': 'API v1 is deprecated'},\n      statusCode: 410,\n    ),\n  ],\n  // Never filter these paths\n  exclusions: ['/api/health', '/api/version'],\n);\n\n// Add the interceptor with filtering\ndio.interceptors.add(\n  CurlInterceptorFactory.withFilters(filterOptions: filterOptions),\n);\n```\n\nFor more detailed documentation on path filtering, see [Path Filtering Guide](doc/PATH_FILTERING.md).\n\n### Option 4: Real-time filter editing with CurlViewer\n\nYou can now edit filter rules directly in the CurlViewer interface:\n\n```dart\nimport 'package:dio_curl_interceptor/dio_curl_interceptor.dart';\n\n// Show CurlViewer with filter editing capabilities\nshowDialog(\n  context: context,\n  builder: (context) =\u003e CurlViewer(\n    displayType: CurlViewerDisplayType.dialog,\n    enablePersistence: true, // Enable filter persistence\n  ),\n);\n\n// Users can now:\n// 1. Click the filters button (🔍) in the CurlViewer header\n// 2. Add, edit, and delete filter rules in real-time\n// 3. Test filter rules against sample requests\n// 4. See immediate effects on API blocking\n```\n\n### Option 5: Using webhook integration\n\nYou can use webhook integration to send cURL logs to Discord channels or Telegram chats for remote logging and team collaboration:\n\n#### Setting up Telegram Webhooks\n\nFor Telegram integration, you need to:\n\n1. **Create a Telegram Bot:**\n   - Message [@BotFather](https://t.me/botfather) on Telegram\n   - Use `/newbot` command and follow the instructions\n   - Save your bot token\n\n2. **Get your Chat ID:**\n   - Start a conversation with your bot\n   - Send any message to the bot\n   - Visit `https://api.telegram.org/bot\u003cYOUR_BOT_TOKEN\u003e/getUpdates`\n   - Find your chat ID in the response (it's a number, can be negative for groups)\n\n3. **Configure the TelegramInspector:**\n   - Use `botToken` and `chatIds` parameters directly\n   - Example: `TelegramInspector(botToken: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', chatIds: [123456789])`\n\n```dart\n// Using manual webhook configuration\ndio.interceptors.add(CurlInterceptor(\n  webhookInspectors: [\n    DiscordInspector(\n      webhookUrls: ['https://discord.com/api/webhooks/your-webhook-url'],\n      includeUrls: ['api.example.com', '/users/'],\n      excludeUrls: ['/healthz'],\n      inspectionStatus: [ResponseStatus.clientError, ResponseStatus.serverError],\n    ),\n    TelegramInspector(\n      botToken: 'YOUR_BOT_TOKEN', // Get from @BotFather\n      chatIds: [-1003019608685], // Get from getUpdates API\n      includeUrls: ['api.example.com'],\n      inspectionStatus: [ResponseStatus.serverError], // Only server errors\n    ),\n  ],\n));\n\n// Manual webhook sending\nfinal discordInspector = DiscordInspector(\n  webhookUrls: ['https://discord.com/api/webhooks/your-webhook-url'],\n);\n\nfinal telegramInspector = TelegramInspector(\n  botToken: 'YOUR_BOT_TOKEN', // Get from @BotFather\n  chatIds: [-1003019608685], // Get from getUpdates API\n);\n\n// Send messages\nawait discordInspector.sendMessage(content: 'Hello from Discord!');\nawait telegramInspector.sendMessage(content: 'Hello from Telegram!');\n\n// Send bug reports\nawait discordInspector.sendBugReport(\n  error: 'Example Error',\n  message: 'An example bug report.',\n  extraInfo: {'userId': 'testUser', 'appVersion': '1.0.0'},\n);\n\nawait telegramInspector.sendBugReport(\n  error: 'Example Error',\n  message: 'An example bug report.',\n  extraInfo: {'userId': 'testUser', 'appVersion': '1.0.0'},\n);\n\n```\n\n### Option 4: Using utility functions directly\n\nIf you don't want to add a full interceptor, you can use the utility functions directly in your code:\n\n```dart\n// Generate a curl command from request options\nfinal dio = Dio();\nfinal response = await dio.get('https://example.com');\n\n// Generate and log a curl command\nCurlUtils.logCurl(response.requestOptions);\n\n// Log response details\nCurlUtils.handleOnResponse(response);\n\n// Cache a successful response\nCurlUtils.cacheResponse(response);\n\n// Log error details\ntry {\n  await dio.get('https://invalid-url.com');\n} on DioException catch (e) {\n  CurlUtils.handleOnError(e);\n\n  // Cache an error response\n  CurlUtils.cacheError(e);\n}\n\n## Dio Cache Storage\n\n### Public Flutter Widget: cURL Log Viewer\n\nShow pre-built popup cURL log viewer widget with `showCurlViewer(context)`:\n\n```dart\nElevatedButton(\n  onPressed: () =\u003e showCurlViewer(context),\n  child: const Text('View cURL Logs'),\n);\n```\n\nThe log viewer supports:\n\n- Search and filter by status code, date range, or text\n- Copy cURL command\n- Clear all logs\n- Enhanced sharing functionality with improved system integration\n- Better error handling and UI responsiveness\n\n### Floating Bubble Overlay\n\nFor a non-intrusive debugging experience, use the floating bubble overlay that wraps your main app content:\n\n```dart\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        body: CurlBubble(\n          // Wrap your main app content\n          body: YourMainContent(),\n          controller: BubbleOverlayController(),\n          style: BubbleStyle(\n            initialPosition: const Offset(50, 200),\n            snapToEdges: false, // Stays where you drag it\n          ),\n          onExpanded: () =\u003e debugPrint('Bubble expanded'),\n          onMinimized: () =\u003e debugPrint('Bubble minimized'),\n        ),\n      ),\n    );\n  }\n}\n```\n\n#### Bubble Features\n\n- **Draggable**: Drag the bubble around the screen\n- **Free Positioning**: Stays where you drag it (no auto-snapping by default)\n- **Expandable**: Tap to expand and view cURL logs\n- **Non-intrusive**: Stays on top without blocking your app\n- **Controller-based**: Full programmatic control via `BubbleOverlayController`\n- **Resizable**: Expand and resize the bubble content\n- **Customizable**: Use custom widgets for minimized and expanded states\n\n\u003e **📖 Complete Integration Guide**: For detailed bubble integration instructions, custom configurations, programmatic control, and best practices, see our comprehensive [Bubble Integration Guide](doc/BUBBLE_INTEGRATION_GUIDE.md).\n\n\u003e **Note**: File export functionality has been removed in v3.3.3. Use copy/share features instead.\n\n### Cache Storage Initialization\n\nBefore using caching or the log viewer, initialize storage in your `main()`:\n\n```dart\nvoid main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n  await CachedCurlService.init();\n  runApp(const MyApp());\n}\n```\n\n\u003e **Note**: In v3.3.3, `CachedCurlStorage` was renamed to `CachedCurlService`. See [MIGRATION.md](MIGRATION.md) for details.\n\n## Screenshots\n\n### Simultaneous (log the curl and response (error) together)\n\n\u003cimg src=\"https://raw.githubusercontent.com/venhdev/dio_curl_interceptor/refs/heads/main/screenshots/image-simultaneous.png\" width=\"300\" alt=\"Simultaneous Screenshot\"\u003e\n\n### Chronological (log the curl immediately after the request is made)\n\n\u003cimg src=\"https://raw.githubusercontent.com/venhdev/dio_curl_interceptor/refs/heads/main/screenshots/image-chronological.png\" width=\"300\" alt=\"Chronological Screenshot\"\u003e\n\n### Cached Viewer\n\n\u003cimg src=\"https://raw.githubusercontent.com/venhdev/dio_curl_interceptor/refs/heads/main/screenshots/img-cached-viewer.jpg\" width=\"300\" alt=\"Cached Viewer Screenshot\"\u003e\n\n### Inspect Bug Discord\n\n\u003cimg src=\"https://raw.githubusercontent.com/venhdev/dio_curl_interceptor/refs/heads/main/screenshots/img-inspect-bug-discord.png\" width=\"300\" alt=\"Inspect Bug Discord Screenshot\"\u003e\n\n### Inspect cURL Discord\n\n\u003cimg src=\"https://raw.githubusercontent.com/venhdev/dio_curl_interceptor/refs/heads/main/screenshots/img-inspect-curl-discord.png\" width=\"300\" alt=\"Inspect cURL Discord Screenshot\"\u003e\n\n## License\n\nThis project is licensed under the MIT License - see the LICENSE file for details.\n\n- **Repository**: [GitHub](https://github.com/venhdev/dio_curl_interceptor)\n- **Bug Reports**: Please file issues on the [GitHub repository](https://github.com/venhdev/dio_curl_interceptor/issues)\n- **Feature Requests**: Feel free to suggest new features through GitHub issues\n\n[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/venhdev)\n\nContributions are welcome! Please feel free to submit a Pull Request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvenhdev%2Fdio_curl_interceptor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvenhdev%2Fdio_curl_interceptor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvenhdev%2Fdio_curl_interceptor/lists"}