PRIV ProtocolPRIV Docs
Plugin

Earnings

Track your PRIV token earnings and claim rewards from data sharing.

Earnings

The PRIV extension tracks your earnings from data sharing and lets you claim PRIV tokens to your connected wallet.


Earnings Overview

Your earnings come from data you share being purchased on the DataXchange marketplace.

flowchart LR
    A[Share Data] --> B[Data Aggregated]
    B --> C[Listed on Marketplace]
    C --> D[Advertiser Purchases]
    D --> E[Revenue Distributed]
    E --> F[Your Earnings]

Earnings Dashboard

The extension displays your earnings in real-time.

Balance Display

FieldDescription
Available BalancePRIV tokens ready to claim
Pending BalanceEarnings being processed
Lifetime EarningsTotal earned all time

Header View

The extension header shows:

  • Current available balance
  • Pending amount (if any)
  • Wallet connection status
  • Last sync time

[Screenshot: Extension header showing balance of 127.50 PRIV with pending 12.30 PRIV]


Earnings Data Structure

User Earnings

interface UserEarnings {
  totalEarned: number;     // Lifetime total
  pendingEarnings: number; // Processing
  lastClaimDate: string | null; // Last claim
  weeklyEarnings: number[]; // Last 7 days
  monthlyEstimate: number; // Projected
}

User Balance

interface UserBalance {
  available: number;  // Ready to claim
  pending: number;    // Being processed
  lifetime: number;   // All-time total
  currency: string;   // "PRIV"
}

Earnings Tracking

Fetching Earnings

The extension fetches earnings from the background service worker:

// Request earnings from background
const response = await chrome.runtime.sendMessage({
  type: 'GET_EARNINGS'
});

if (response.success) {
  const earnings = response.data as UserEarnings;
  console.log('Total earned:', earnings.totalEarned);
  console.log('Pending:', earnings.pendingEarnings);
}

Using the Earnings Hook

import { useEarnings } from '@/popup/hooks';

function EarningsDisplay() {
  const {
    earnings,
    stats,
    isLoading,
    error,
    refresh,
    claimEarnings
  } = useEarnings(walletAddress);

  if (isLoading) return <Spinner />;
  if (error) return <Error message={error} />;

  return (
    <div>
      <p>Total: {earnings.totalEarned} PRIV</p>
      <p>Pending: {earnings.pendingEarnings} PRIV</p>
      <button onClick={refresh}>Refresh</button>
    </div>
  );
}

Weekly Earnings Chart

The extension displays a 7-day earnings history.

Chart Data

// Weekly earnings array (last 7 days)
const weeklyEarnings = [
  2.5,   // 7 days ago
  3.2,   // 6 days ago
  1.8,   // 5 days ago
  4.1,   // 4 days ago
  2.9,   // 3 days ago
  3.7,   // 2 days ago
  2.3    // Yesterday
];

Chart Component

function EarningsHistory({ weeklyEarnings }: { weeklyEarnings: number[] }) {
  const maxEarning = Math.max(...weeklyEarnings);
  const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

  return (
    <div className="flex items-end gap-1 h-20">
      {weeklyEarnings.map((earning, index) => {
        const height = maxEarning > 0
          ? (earning / maxEarning) * 100
          : 0;

        return (
          <div key={index} className="flex flex-col items-center flex-1">
            <div
              className="w-full bg-primary rounded-t"
              style={{ height: `${height}%` }}
            />
            <span className="text-xs mt-1">{days[index]}</span>
          </div>
        );
      })}
    </div>
  );
}

[Screenshot: Weekly earnings bar chart showing daily earnings over 7 days]


Claiming Earnings

Claim Requirements

RequirementValue
Minimum claim10 PRIV
NetworkBase (mainnet)
GasPaid by user (~$0.01)
Processing timeInstant

Claim Process

  1. Ensure you have at least 10 PRIV available
  2. Click Claim in the extension
  3. Confirm the transaction in your wallet
  4. Tokens are sent to your connected address
sequenceDiagram
    participant User
    participant Extension
    participant API as PRIV API
    participant Contract as Smart Contract
    participant Wallet

    User->>Extension: Click Claim
    Extension->>API: Request Claim
    API->>Contract: Execute Transfer
    Contract->>Wallet: Send PRIV Tokens
    Contract-->>API: TX Hash
    API-->>Extension: Success
    Extension->>Extension: Refresh Balance
    Extension-->>User: Show Success

Claim Code

async function claimEarnings(): Promise<boolean> {
  if (!walletAddress) {
    showError('No wallet connected');
    return false;
  }

  const response = await chrome.runtime.sendMessage({
    type: 'CLAIM_EARNINGS',
  });

  if (response.success) {
    const { txHash, amount } = response.data;
    showSuccess(`Claimed ${amount} PRIV! TX: ${txHash}`);
    await refreshEarnings(); // Update display
    return true;
  }

  showError(response.error ?? 'Claim failed');
  return false;
}

Earnings Calculation

How Earnings Are Calculated

Your share of each data sale is calculated as:

Your Share = (Your Data Points / Total Pool) × (Sale Price - Platform Fee)

Factors Affecting Earnings

FactorImpact
Data VolumeMore data = higher share
Data TypesHigh-value types earn more
Data QualityDiverse patterns valued more
Market DemandVaries by category
CompetitionMore users = smaller shares

Example Calculation

Dataset sold for: 1000 PRIV
Total contributors: 500 users
Your data points: 2000
Total pool points: 100,000

Your share = (2000 / 100,000) × (1000 - 100)
           = 0.02 × 900
           = 18 PRIV

Earnings by Data Type

Different data types have different values based on market demand.

Data TypeBase RateMarket MultiplierTypical Earnings
Shopping BehaviorHigh1.5x$5-15/month
Social InteractionsHigh1.3x$4-12/month
Ad ImpressionsMedium1.2x$3-10/month
Search QueriesMedium1.1x$3-8/month
Browsing HistoryLow1.0x$2-6/month
Content PreferencesLow1.0x$2-5/month
Location DataLow0.8x$1-4/month

Caching and Performance

Cache Strategy

Earnings are cached to reduce API calls and improve performance:

interface EarningsCache {
  earnings: UserEarnings | null;
  balance: UserBalance | null;
  lastFetched: number | null;
  expiresAt: number | null;
}

Cache Duration

DataCache Time
Earnings5 minutes
Balance5 minutes
Stats5 minutes

Cache Refresh

Cache is automatically refreshed:

  • Every 5 minutes via alarm
  • After claiming earnings
  • After data submission
  • On manual refresh
// Invalidate cache after claim
dataCache.lastFetched = 0;

// Force refresh
await chrome.runtime.sendMessage({ type: 'FLUSH_QUEUE' });

Error Handling

Empty State

When no wallet is connected or no earnings exist:

const EMPTY_EARNINGS: UserEarnings = {
  totalEarned: 0,
  pendingEarnings: 0,
  lastClaimDate: null,
  weeklyEarnings: [0, 0, 0, 0, 0, 0, 0],
  monthlyEstimate: 0,
};

const EMPTY_BALANCE: UserBalance = {
  available: 0,
  pending: 0,
  lifetime: 0,
  currency: 'PRIV',
};

API Errors

The extension handles API errors gracefully:

async function fetchEarnings(walletAddress: string | null) {
  // No wallet = return empty (not error)
  if (!walletAddress) {
    return { success: true, data: EMPTY_EARNINGS };
  }

  try {
    const response = await getEarnings(walletAddress);

    if (response.success) {
      return response;
    }

    // Return cached data if available
    const cached = await getCachedEarnings();
    if (cached) {
      return { success: true, data: cached };
    }

    // Return empty as fallback
    return { success: false, error: response.error, data: EMPTY_EARNINGS };
  } catch (error) {
    return { success: false, error: error.message, data: EMPTY_EARNINGS };
  }
}

User Statistics

Along with earnings, the extension tracks user statistics:

interface UserStats {
  privBalance: number;      // Current token balance
  totalDataPoints: number;  // Data submitted
  activeDataTypes: number;  // Enabled categories
  ranking: number;          // Contributor ranking
}

Stats Display

function StatsCard({ stats }: { stats: UserStats }) {
  return (
    <div className="grid grid-cols-2 gap-4">
      <Stat
        label="Data Points"
        value={stats.totalDataPoints.toLocaleString()}
      />
      <Stat
        label="Active Types"
        value={`${stats.activeDataTypes}/7`}
      />
      <Stat
        label="Ranking"
        value={`#${stats.ranking.toLocaleString()}`}
      />
      <Stat
        label="Balance"
        value={`${stats.privBalance.toFixed(2)} PRIV`}
      />
    </div>
  );
}

Maximizing Earnings

Tips for Higher Earnings

  1. Enable All Data Types: More data types = more earnings
  2. Browse Consistently: Regular activity increases data volume
  3. Diverse Browsing: Visit different site categories
  4. Keep Extension Active: Don't disable data sharing
  5. Update Regularly: Latest version has optimizations

What Decreases Earnings

  • Disabling data types
  • Using blocklists heavily
  • Infrequent browsing
  • Clearing extension data
  • Network connectivity issues

Next Steps