A Mindful Browser Extension for Digital Wellbeing

Spread the love


Table of Contents

Introduction

In today’s hyper-connected digital landscape, it’s increasingly difficult to maintain a healthy relationship with technology. Constant notifications, endless content streams, and addictive design patterns can lead to digital fatigue, decreased productivity, and even mental health challenges.

To address these issues, the team behind Clarity Pro developed an innovative browser extension that uses behavioral psychology principles to disrupt harmful digital patterns constructively. Rather than resorting to aggressive blocking or restrictive time limits, Clarity Pro offers gentle, context-aware interventions that gradually guide users towards more mindful digital habits.

In this technical deep-dive, we’ll explore the architecture, algorithms, and implementation details behind Clarity Pro’s intelligent disruption engine. We’ll discuss the challenges the team faced, the solutions they developed, and the best practices they followed to create a robust, scalable, and user-friendly tool for digital well-being.

System Architecture Overview

At its core, Clarity Pro consists of three main components:

  1. Browser Extension: The user-facing interface that integrates with the user’s web browser, tracks usage patterns, and delivers contextual interventions.
  2. Backend API: A serverless, event-driven backend that processes usage data, generates insights, and manages user preferences.
  3. Machine Learning Models: A suite of ML models trained on user behavior data to predict optimal intervention timing and content.

Browser Extension Implementation

The Clarity Pro browser extension is built using TypeScript and React, leveraging the WebExtensions API for cross-browser compatibility. The extension consists of several key modules:

1. Activity Tracker

The ActivityTracker module is responsible for capturing user activity data, such as:

  • Active tab URL and title
  • Scroll position and interaction events
  • Keyboard and mouse activity
  • Tab switching frequency

Here’s a simplified version of the activity tracking logic:

class ActivityTracker {
  private readonly ACTIVITY_THRESHOLD = 5_000; // 5 seconds

  private tabActivity: Map = new Map();

  constructor() {
    browser.tabs.onActivated.addListener(this.handleTabActivated);
    browser.tabs.onUpdated.addListener(this.handleTabUpdated);
    browser.idle.onStateChanged.addListener(this.handleIdleStateChanged);
  }

  private async handleTabActivated({ tabId }: { tabId: number }) {
    const tab = await browser.tabs.get(tabId);
    this.tabActivity.set(tabId, this.createTabActivity(tab));
  }

  private handleTabUpdated(
    tabId: number,
    changeInfo: { url?: string },
    tab: browser.tabs.Tab
  ) {
    if (changeInfo.url) {
      this.tabActivity.set(tabId, this.createTabActivity(tab));
    }
  }

  private handleIdleStateChanged(newState: browser.idle.IdleState) {
    if (newState === 'active') {
      this.tabActivity.forEach((activity, tabId) => {
        activity.idleTime = 0;
        this.tabActivity.set(tabId, activity);
      });
    }
  }

  private createTabActivity(tab: browser.tabs.Tab): TabActivity {
    return {
      url: tab.url,
      title: tab.title,
      startTime: Date.now(),
      scrollPosition: 0,
      idleTime: 0,
      // ... other activity metrics
    };
  }

  // ... methods to track scroll, interaction, and idle time
}

The ActivityTracker listens for various browser events, such as tab activation, URL changes, and idle state, and maintains a tabActivity map to store the current activity data for each tab.

2. Intervention Engine

The InterventionEngine module determines when and how to deliver mindful disruptions based on the user’s current activity and the insights generated by the backend ML models. It defines an extensible Intervention interface and provides a set of built-in intervention types, such as:

  • Breathing exercises
  • Mindful reflection prompts
  • Contextual content recommendations
  • Gradual UX adjustments (e.g., slowing page load times)

Here’s an example implementation of the Intervention interface and a simple breathing exercise intervention:

interface Intervention {
  id: string;
  type: InterventionType;
  shouldTrigger: (activity: TabActivity, insights: Insights) => boolean;
  render: () => void;
}

class BreathingExercise implements Intervention {
  id = 'breathing_exercise';
  type = InterventionType.Overlay;

  shouldTrigger(activity: TabActivity, insights: Insights): boolean {
    return (
      activity.idleTime > 30_000 && // 30 seconds of idle time
      insights.stressLevel > 0.7 // high predicted stress level
    );
  }

  render() {
    const overlayElement = document.createElement('div');
    overlayElement.innerHTML = `
      

Take a mindful breath

Inhale deeply for 4 seconds, hold for 4, exhale for 6.

`; document.body.appendChild(overlayElement); // ... animate breathing exercise } }

The InterventionEngine periodically checks the user’s activity and insights data against each registered intervention’s shouldTrigger condition. When an intervention is triggered, the engine calls its render method to display the disruption to the user.

3. Insights Sync

The InsightsSync module communicates with the backend API to send activity data and retrieve ML-generated insights. It uses a throttled, batched approach to minimize network overhead and optimize performance.

class InsightsSync {
  private readonly SYNC_INTERVAL = 60_000; // 1 minute
  private readonly BATCH_SIZE = 100;

  private activityQueue: TabActivity[] = [];

  constructor(private readonly activityTracker: ActivityTracker) {
    setInterval(this.syncInsights, this.SYNC_INTERVAL);
  }

  private async syncInsights() {
    const batchedActivities = this.activityQueue.splice(0, this.BATCH_SIZE);
    if (batchedActivities.length === 0) {
      return;
    }

    try {
      const insights = await fetch('/api/insights', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(batchedActivities),
      }).then((res) => res.json());

      // ... update intervention engine with new insights
    } catch (err) {
      console.error('Error syncing insights:', err);
      this.activityQueue.unshift(...batchedActivities);
    }
  }

  enqueueActivity(activity: TabActivity) {
    this.activityQueue.push(activity);
  }
}

The InsightsSync module maintains an activityQueue to store activity data and periodically sends batches of data to the backend API. The backend returns a set of ML-generated insights, which are then used to update the InterventionEngine‘s triggering logic.

Backend API and ML Pipeline

The Clarity Pro backend is built on a serverless, event-driven architecture using AWS Lambda, API Gateway, and DynamoDB. When the browser extension sends a batch of activity data, it triggers a Lambda function that processes the data and updates the user’s activity history in DynamoDB.

The Lambda function also publishes the activity data to an Amazon Kinesis stream, which feeds into a real-time ML pipeline. The pipeline, implemented using Amazon SageMaker, performs the following steps:

  1. Data Preprocessing: Cleans, normalizes, and transforms the raw activity data into a format suitable for training ML models.
  2. Feature Engineering: Extracts relevant features from the preprocessed data, such as engagement metrics, content categories, and time-based patterns.
  3. Model Training: Trains a set of ML models to predict user-specific insights, such as stress levels, focus duration, and content preferences.
  4. Insights Generation: Applies the trained models to the latest activity data to generate real-time insights for each user.

The generated insights are then stored in DynamoDB and made available to the browser extension via the /api/insights endpoint.

Here’s a simplified example of the insights generation process using a stress level prediction model:

import boto3
import numpy as np
from sklearn.linear_model import LogisticRegression

def train_stress_model(user_data):
    features = extract_features(user_data)
    labels = user_data['stress_level']
    
    model = LogisticRegression()
    model.fit(features, labels)
    
    return model

def predict_stress_level(model, activity_data):
    features = extract_features([activity_data])
    stress_level = model.predict_proba(features)[0][1]
    
    return stress_level

def lambda_handler(event, context):
    user_id = event['user_id']
    activity_data = event['activity_data']
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('user_activity')
    
    response = table.query(KeyConditionExpression=Key('user_id').eq(user_id))
    user_data = response['Items']
    
    stress_model = train_stress_model(user_data)
    stress_level = predict_stress_level(stress_model, activity_data)
    
    insights = {
        'user_id': user_id,
        'timestamp': activity_data['timestamp'],
        'stress_level': stress_level,
        # ... other insights
    }
    
    table.put_item(Item=insights)
    
    return insights

In this example, the train_stress_model function trains a logistic regression model on the user’s historical activity data to predict stress levels. The predict_stress_level function applies the trained model to the latest activity data to generate a real-time stress level insight.

Performance Optimization and Scaling

To ensure Clarity Pro remains performant and scalable as the user base grows, the team implemented several optimization techniques:

  1. Client-side Throttling: The browser extension throttles the activity tracking and insights syncing processes to reduce CPU and network usage.
  2. Serverless Architecture: The backend API and ML pipeline are built on AWS Lambda, which automatically scales based on incoming request volume.
  3. Data Partitioning: The DynamoDB tables are partitioned by user ID to evenly distribute read and write throughput and minimize hot partitions.
  4. Caching: The backend API caches frequently accessed insights using Amazon ElastiCache to reduce latency and database load.
  5. Incremental Learning: The ML pipeline uses incremental learning techniques to update the models in real-time as new activity data arrives, rather than retraining from scratch.

Here’s an example of how incremental learning can be implemented using scikit-learn’s partial_fit method:

def update_stress_model(model, activity_data, stress_level):
    features = extract_features([activity_data])
    model.partial_fit(features, [stress_level], classes=[0, 1])
    
    return model

def lambda_handler(event, context):
    # ... retrieve user data and train initial model
    
    for activity_data in event['activity_data']:
        stress_level = predict_stress_level(stress_model, activity_data)
        stress_model = update_stress_model(stress_model, activity_data, stress_level)
    
    # ... save updated model and generate insights

By incrementally updating the stress model with each new activity data point, the ML pipeline can adapt to changing user behavior in real time without full retraining.

Testing and Deployment

To maintain a high quality codebase and catch potential issues early, the Clarity Pro team implemented a comprehensive testing strategy:

  1. Unit Tests: A suite of unit tests using Jest and Mocha covers each module and component in the browser extension and backend API.
  2. Integration Tests: End-to-end integration tests are run using Selenium and Puppeteer to ensure the browser extension and backend API work together seamlessly.
  3. Load Tests: The backend API and ML pipeline are subjected to load testing using tools like Artillery and Locust to verify they can handle expected traffic volumes.
  4. A/B Tests: New features and interventions are rolled out to a subset of users in an A/B testing framework to measure their impact on engagement and wellbeing metrics.

The team uses a CI/CD pipeline built on GitHub Actions to automatically run tests, build artifacts, and deploy updates to production. The pipeline is triggered on every push to the main branch and follows a blue-green deployment model to minimize downtime and enable quick rollbacks if needed.

Conclusion

Clarity Pro represents a novel approach to promoting digital wellbeing by leveraging behavioral psychology principles and ML-driven personalization. The browser extension empowers users to build more mindful digital habits without resorting to restrictive blocking or time limits by delivering gentle, contextual interventions at the right moments.

The technical architecture behind Clarity Pro, with its focus on serverless computing, real-time ML pipelines, and client-side performance optimization, showcases best practices for building scalable, data-driven applications. As the event’s technical evaluators, including Nisarg Shah, highlighted, the project’s efficient memory management and modular design patterns contribute to its overall robustness and maintainability.

Looking ahead, the Clarity Pro team plans to expand the range of available interventions, explore more advanced ML techniques for personalization, and potentially integrate with other digital wellbeing tools and platforms. By open-sourcing key components of the codebase and sharing their learnings with the wider developer community, they hope to inspire further innovation in the field of mindful technology.


Share this content:

I am a passionate blogger with extensive experience in web design. As a seasoned YouTube SEO expert, I have helped numerous creators optimize their content for maximum visibility.

Leave a Comment