<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Satyam Gawali</title>
    <description>The latest articles on DEV Community by Satyam Gawali (@satyam_gawali_4e7bc3d92e0).</description>
    <link>https://dev.to/satyam_gawali_4e7bc3d92e0</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3920839%2F8db1fb24-ac67-46bd-a4cd-fe16b1aca24e.png</url>
      <title>DEV Community: Satyam Gawali</title>
      <link>https://dev.to/satyam_gawali_4e7bc3d92e0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/satyam_gawali_4e7bc3d92e0"/>
    <language>en</language>
    <item>
      <title>How to Redact Sensitive Tokens &amp; PII from Flutter Logs Before They Reach Memory</title>
      <dc:creator>Satyam Gawali</dc:creator>
      <pubDate>Sat, 07 Nov 2026 14:48:25 +0000</pubDate>
      <link>https://dev.to/satyam_gawali_4e7bc3d92e0/how-to-redact-sensitive-tokens-pii-from-flutter-logs-before-they-reach-memory-5b4k</link>
      <guid>https://dev.to/satyam_gawali_4e7bc3d92e0/how-to-redact-sensitive-tokens-pii-from-flutter-logs-before-they-reach-memory-5b4k</guid>
      <description>&lt;p&gt;When testing Flutter applications on physical devices, having an in-app logging dashboard can make debugging significantly easier.&lt;/p&gt;

&lt;p&gt;Whether you're testing staging builds, investigating API responses, or reviewing application behavior during QA sessions, on-device logs provide valuable visibility without requiring a laptop or Flutter DevTools.&lt;/p&gt;

&lt;p&gt;But there is one important problem that developers often overlook:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when your application logs sensitive information?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a typical API response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1029&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"developer@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJIUzI1NiIs..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refreshToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"some_refresh_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+911234567890"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Displaying this response directly inside an in-app debugging dashboard could expose authentication credentials and personal information to anyone who can access the device or its screen.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain how we approached this problem while building an open-source Flutter debugging toolkit called &lt;strong&gt;debug_bubble&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Redacting Logs Is More Complicated Than It Looks
&lt;/h2&gt;

&lt;p&gt;A simple string replacement might work for a basic example, but real application logs contain much more complex data.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nested JSON objects.&lt;/li&gt;
&lt;li&gt;Lists containing multiple objects.&lt;/li&gt;
&lt;li&gt;CamelCase and snake_case API fields.&lt;/li&gt;
&lt;li&gt;Authentication headers and bearer tokens.&lt;/li&gt;
&lt;li&gt;Sensitive values embedded inside strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A reliable logging pipeline should sanitize data before it reaches the in-memory storage layer.&lt;/p&gt;

&lt;p&gt;If sensitive information enters your log buffer before sanitization, it may remain accessible through searching, viewing, copying, or exporting logs.&lt;/p&gt;

&lt;p&gt;We designed the redaction pipeline in &lt;code&gt;debug_bubble&lt;/code&gt; to process data during log ingestion rather than waiting until the dashboard renders it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Key-Based Sensitive Data Redaction
&lt;/h2&gt;

&lt;p&gt;The first layer uses configurable sensitive-key matching.&lt;/p&gt;

&lt;p&gt;Instead of checking only exact field names, &lt;code&gt;debug_bubble&lt;/code&gt; supports normalized key matching.&lt;/p&gt;

&lt;p&gt;For example, these variations can be identified consistently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;accessToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;access_token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ACCESS_TOKEN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;access-token&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The built-in sensitive-key rules cover common fields such as passwords, tokens, authorization headers, cookies, secrets, and credentials.&lt;/p&gt;

&lt;p&gt;There is also exact token-based matching for fields such as PIN, OTP, CVV, CVC, and session identifiers.&lt;/p&gt;

&lt;p&gt;This helps catch sensitive values across different API naming conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Regex-Based Value Pattern Redaction
&lt;/h2&gt;

&lt;p&gt;Key-based matching alone isn't sufficient.&lt;/p&gt;

&lt;p&gt;Sometimes sensitive information appears inside a normal string rather than a dedicated JSON field.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;DebugLog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;'Authorization response received'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;json:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'message'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bearer eyJhbGciOiJIUzI1NiIs...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The field name &lt;code&gt;message&lt;/code&gt; doesn't indicate that its value contains an authentication token.&lt;/p&gt;

&lt;p&gt;That's where regex-based value scanning becomes useful.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DebugRedactionConfig&lt;/code&gt; supports custom regular expressions for detecting sensitive patterns.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;DebugRedactionConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;valuePatterns:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="sx"&gt;r'\bBearer\s+[A-Za-z0-9._~+/-]+=*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;caseSensitive:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows developers to configure additional masking rules for bearer tokens, email addresses, and other application-specific data.&lt;/p&gt;

&lt;p&gt;The matching values are replaced with the configured replacement string.&lt;/p&gt;

&lt;p&gt;By default:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[REDACTED]&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Handling False Positives with an Allowlist
&lt;/h2&gt;

&lt;p&gt;There is another interesting problem with sensitive-key matching.&lt;/p&gt;

&lt;p&gt;Consider these fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokenCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cardType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"debit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"secretary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A broad substring-based rule could incorrectly identify some legitimate fields as sensitive.&lt;/p&gt;

&lt;p&gt;To handle this, we introduced &lt;code&gt;allowedKeys&lt;/code&gt; in version 0.2.0.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;DebugRedactionConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;allowedKeys:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'tokenCount'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'cardType'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'secretary'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Allowlisted fields bypass key-based sensitive matching when their normalized keys match exactly.&lt;/p&gt;

&lt;p&gt;However, there is an important security detail:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allowlisting a key does not disable regex-based value redaction.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an allowlisted field contains a recognizable bearer token or another configured sensitive pattern, its value is still masked.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Redaction Before Storage
&lt;/h2&gt;

&lt;p&gt;One of the most important decisions we made was where sanitization should happen.&lt;/p&gt;

&lt;p&gt;A basic implementation might follow this approach:&lt;/p&gt;

&lt;p&gt;Capture Log → Store Raw Log → Render Dashboard → Hide Sensitive Values&lt;/p&gt;

&lt;p&gt;The problem is that raw sensitive information has already entered memory.&lt;/p&gt;

&lt;p&gt;Our approach is different:&lt;/p&gt;

&lt;p&gt;Capture Log → Redaction Pipeline → Sanitized Log Entry → Bounded Memory Buffer → Dashboard / Search / Export&lt;/p&gt;

&lt;p&gt;This ensures that stored log entries contain sanitized data rather than relying exclusively on UI-level masking.&lt;/p&gt;

&lt;p&gt;We also implemented bounded payload traversal to prevent excessively large or deeply nested objects from consuming unnecessary resources.&lt;/p&gt;

&lt;p&gt;The implementation includes limits for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum traversal depth.&lt;/li&gt;
&lt;li&gt;Maximum processed nodes.&lt;/li&gt;
&lt;li&gt;Maximum collection items.&lt;/li&gt;
&lt;li&gt;Maximum string length.&lt;/li&gt;
&lt;li&gt;Circular-reference handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These limits help keep diagnostic logging predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Using debug_bubble in a Flutter Application
&lt;/h2&gt;

&lt;p&gt;Instead of implementing a custom logging overlay, storage engine, and sanitization pipeline separately, developers can use our package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add debug_bubble
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Initialize the logging engine&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:debug_bubble/debug_bubble.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;DebugLog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DebugBubbleConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;enabled:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;maxEntries:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;minLevel:&lt;/span&gt; &lt;span class="n"&gt;DebugLogLevel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;consoleOutput:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;captureUncaughtErrors:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Attach the floating dashboard&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DebugBubble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shrink&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;HomeScreen&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The floating bubble provides access to the in-app debugging dashboard without requiring developers to manually manage navigation routes.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Configuring Custom Redaction Rules
&lt;/h2&gt;

&lt;p&gt;You can extend the default security rules with application-specific fields.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DebugRedactionConfig&lt;/code&gt; supports custom sensitive keys, token matching, allowlisted keys, regex-based patterns, and replacement strings.&lt;/p&gt;

&lt;p&gt;This allows developers to combine built-in rules with their own application-specific requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. What About Production Builds?
&lt;/h2&gt;

&lt;p&gt;Another important consideration when building debugging utilities is their impact on production applications.&lt;/p&gt;

&lt;p&gt;We designed &lt;code&gt;debug_bubble&lt;/code&gt; to be completely inert in release mode.&lt;/p&gt;

&lt;p&gt;When compiled with &lt;code&gt;kReleaseMode&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logging calls are dropped immediately.&lt;/li&gt;
&lt;li&gt;No log entries are stored.&lt;/li&gt;
&lt;li&gt;Background error hooks are not installed.&lt;/li&gt;
&lt;li&gt;The floating overlay is not created.&lt;/li&gt;
&lt;li&gt;The widget returns the original child subtree.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means developers can integrate the package into their application architecture without introducing an active debugging dashboard into release builds.&lt;/p&gt;

&lt;p&gt;The package also has &lt;strong&gt;zero third-party runtime dependencies&lt;/strong&gt;, relying on Flutter and Dart standard libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building an in-app logging dashboard is not just about displaying messages on a screen.&lt;/p&gt;

&lt;p&gt;Memory management, payload handling, error interception, and sensitive-data protection are equally important parts of the architecture.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;debug_bubble&lt;/code&gt;, we wanted to bring these capabilities together into a reusable Flutter debugging toolkit.&lt;/p&gt;

&lt;p&gt;The project is open source, and contributions, feedback, and suggestions are welcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore the project:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pub.dev: &lt;a href="https://pub.dev/packages/debug_bubble" rel="noopener noreferrer"&gt;https://pub.dev/packages/debug_bubble&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Satyam-Gawali/debug_bubble" rel="noopener noreferrer"&gt;https://github.com/Satyam-Gawali/debug_bubble&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear how other Flutter developers approach sensitive-data redaction in their debugging pipelines.&lt;/p&gt;

&lt;p&gt;Do you prefer key-based sanitization, regex-based pattern detection, or combining both approaches? Let's discuss!&lt;/p&gt;

</description>
      <category>flutt</category>
      <category>dart</category>
      <category>security</category>
      <category>mobiledev</category>
    </item>
    <item>
      <title>Introducing Chroma Theme 🎨 — A Premium Material 3 Dynamic Theming Engine for Flutter</title>
      <dc:creator>Satyam Gawali</dc:creator>
      <pubDate>Fri, 08 May 2026 22:56:56 +0000</pubDate>
      <link>https://dev.to/satyam_gawali_4e7bc3d92e0/introducing-chroma-theme-a-premium-material-3-dynamic-theming-engine-for-flutter-o6n</link>
      <guid>https://dev.to/satyam_gawali_4e7bc3d92e0/introducing-chroma-theme-a-premium-material-3-dynamic-theming-engine-for-flutter-o6n</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introducing Chroma Theme 🎨&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;A Premium Material 3 Dynamic Theming Engine for Flutter&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Managing themes in Flutter can become complex very quickly, especially when working with Material 3.&lt;/p&gt;

&lt;p&gt;You often need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure dozens of colors&lt;/li&gt;
&lt;li&gt;Support Light and Dark themes&lt;/li&gt;
&lt;li&gt;Add AMOLED and High Contrast modes&lt;/li&gt;
&lt;li&gt;Manage custom palettes&lt;/li&gt;
&lt;li&gt;Persist user preferences&lt;/li&gt;
&lt;li&gt;Write repetitive &lt;code&gt;ThemeData&lt;/code&gt; boilerplate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this, I built &lt;strong&gt;Chroma Theme&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Chroma Theme is a premium, dynamic, and adaptive Material 3 theming engine for Flutter that turns a single seed color into a complete, production-ready theme system.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🎨 Dynamic seed-based color generation&lt;/li&gt;
&lt;li&gt;🌗 Light, Dark, AMOLED, and High Contrast modes&lt;/li&gt;
&lt;li&gt;🎭 20+ professionally curated palettes&lt;/li&gt;
&lt;li&gt;🛠️ Full Material 3 tonal palette access&lt;/li&gt;
&lt;li&gt;🧩 Global component overrides&lt;/li&gt;
&lt;li&gt;💾 Theme persistence support&lt;/li&gt;
&lt;li&gt;🚀 Intuitive &lt;code&gt;BuildContext&lt;/code&gt; extensions&lt;/li&gt;
&lt;li&gt;♿ Accessibility-focused design&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📦 Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chroma_theme&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🚀 Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:chroma_theme/chroma_theme.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ChromaTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;initialMode:&lt;/span&gt; &lt;span class="n"&gt;ChromaThemeMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;initialPalette:&lt;/span&gt; &lt;span class="n"&gt;ChromaPalette&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎨 Dynamic Seeds
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chroma&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSeeds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ChromaSeeds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;primary:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xFF6366F1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🌓 Theme Modes
&lt;/h2&gt;

&lt;p&gt;Supported modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Light&lt;/li&gt;
&lt;li&gt;Dark&lt;/li&gt;
&lt;li&gt;AMOLED&lt;/li&gt;
&lt;li&gt;High Contrast&lt;/li&gt;
&lt;li&gt;System&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎭 Premium Palettes
&lt;/h2&gt;

&lt;p&gt;Chroma Theme includes 20+ curated palettes such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Neon Forest&lt;/li&gt;
&lt;li&gt;Midnight Mint&lt;/li&gt;
&lt;li&gt;Berry Blush&lt;/li&gt;
&lt;li&gt;Ice Latte&lt;/li&gt;
&lt;li&gt;Noir Mauve&lt;/li&gt;
&lt;li&gt;Ocean Signal&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧩 Component Overrides
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;ChromaTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;overrides:&lt;/span&gt; &lt;span class="n"&gt;ChromaOverrides&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;appBarTheme:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;AppBarTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;centerTitle:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  💾 Persistence Support
&lt;/h2&gt;

&lt;p&gt;Save and restore user theme preferences using SharedPreferences, Hive, or any custom storage solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pub.dev: &lt;a href="https://pub.dev/packages/chroma_theme" rel="noopener noreferrer"&gt;https://pub.dev/packages/chroma_theme&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Satyam-Gawali/chroma_theme" rel="noopener noreferrer"&gt;https://github.com/Satyam-Gawali/chroma_theme&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🙌 Feedback Welcome
&lt;/h2&gt;

&lt;p&gt;I’d love to hear your thoughts, suggestions, and contributions.&lt;/p&gt;

&lt;p&gt;If you find the package useful, please consider starring the GitHub repository and sharing your feedback.&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🚀&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>appconfig</category>
    </item>
  </channel>
</rss>
