SDKs & Integrations

React SDK

Hooks, components, and TypeScript types for building Outfame dashboards in React. Tree-shakeable, 12.4 KB gzipped.

FeatureDetails
Package@outfame/react
Version2.6.0
React≥ 18.0
TypeScript≥ 5.0
Bundle size12.4 KB gzipped (tree-shakeable)
LicenseMIT
Sourcegithub.com/outfame/outfame-react

Installation

npm install @outfame/react
# or
yarn add @outfame/react
# or
pnpm add @outfame/react
# or
bun add @outfame/react

Provider setup

Wrap your app with OutfameProvider to initialize auth, caching, and real-time updates.

import { OutfameProvider } from "@outfame/react";

function App() {
  return (
    <OutfameProvider
      apiKey="sk_live_your_api_key"
      options={{
        // Cache growth data for 60 seconds
        cacheTtl: 60000,
        // Automatically refresh follower counts
        revalidateOnFocus: true,
        // Enable real-time WebSocket updates for live growth tracking
        realtime: true,
      }}
    >
      <YourApp />
    </OutfameProvider>
  );
}

Security — Never expose your secret API key in client-side code. Use a proxy endpoint on your server to relay requests. See the Authentication guide for the recommended pattern.


Hooks

Four core hooks for fetching account, analytics, targeting, and engagement data. Each handles loading, errors, caching, and revalidation.

useAccount

Fetch account details and status.

import { useAccount } from "@outfame/react";

function AccountHeader({ accountId }: { accountId: string }) {
  const { data: account, isLoading, error, mutate } = useAccount(accountId);

  if (isLoading) return <Skeleton />;
  if (error) return <ErrorDisplay error={error} />;

  return (
    <div className="flex items-center gap-4">
      <img
        src={account.avatar_url}
        alt={account.instagram_username}
        className="h-16 w-16 rounded-full"
      />
      <div>
        <h2 className="text-xl font-bold">@{account.instagram_username}</h2>
        <p className="text-gray-500">
          {account.followers_count.toLocaleString()} followers
        </p>
        <span className={`badge ${
          account.status === "active" ? "badge-green" : "badge-yellow"
        }`}>
          {account.status === "active" ? "Growing" : "Paused"}
        </span>
      </div>
    </div>
  );
}

useAnalytics

Growth metrics, engagement rates, and audience demographics with time range control.

import { useAnalytics } from "@outfame/react";

function GrowthMetrics({ accountId }: { accountId: string }) {
  const {
    data: analytics,
    isLoading,
    period,
    setPeriod,
  } = useAnalytics(accountId, {
    period: "30d",
    granularity: "daily",
  });

  if (isLoading) return <MetricsSkeleton />;

  return (
    <div>
      <div className="grid grid-cols-4 gap-6">
        <Metric label="Net Growth" value={`+${analytics.net_growth}`} />
        <Metric label="Followers Gained" value={analytics.followers_gained} />
        <Metric label="Engagement Rate" value={`${analytics.engagement_rate}%`} />
        <Metric label="Follow-back Rate" value={`${analytics.follow_back_rate}%`} />
      </div>

      {/* Growth trend — shows real follower gains over time */}
      <div className="mt-6">
        {analytics.data_points.map((point) => (
          <div key={point.date} className="flex justify-between">
            <span>{point.date}</span>
            <span className="font-medium">+{point.net} followers</span>
          </div>
        ))}
      </div>
    </div>
  );
}

useTargeting

Read and update targeting config — competitors, hashtags, locations, and AI optimization settings.

import { useTargeting } from "@outfame/react";

function TargetingEditor({ accountId }: { accountId: string }) {
  const {
    data: config,
    update,
    suggestions,
    isUpdating,
  } = useTargeting(accountId);

  const handleAddCompetitor = async (username: string) => {
    await update({
      competitor_accounts: [...config.competitor_accounts, username],
    });
  };

  const handleApplySuggestions = async () => {
    const aiSuggestions = await suggestions({ goal: "growth" });

    await update({
      competitor_accounts: aiSuggestions.add_competitors.map((s) => s.username),
      hashtags: aiSuggestions.add_hashtags.map((s) => s.tag),
      ai_optimization: {
        enabled: true,
        mode: "balanced",
        quality_threshold: 0.75,
      },
    });
  };

  return (
    <div className="space-y-6">
      <section>
        <h3>Competitor Accounts</h3>
        <p className="text-sm text-gray-500">
          Followers of these accounts will be targeted.
        </p>
        <div className="flex flex-wrap gap-2">
          {config.competitor_accounts.map((username) => (
            <span key={username} className="rounded-full bg-gray-100 px-3 py-1">
              @{username}
            </span>
          ))}
        </div>
      </section>

      <button onClick={handleApplySuggestions} disabled={isUpdating}>
        {isUpdating ? "Applying..." : "Apply AI Suggestions"}
      </button>
    </div>
  );
}

useEngagement

Live engagement activity, daily limits, and pause/resume controls.

import { useEngagement } from "@outfame/react";

function EngagementPanel({ accountId }: { accountId: string }) {
  const {
    stats,
    activity,
    pause,
    resume,
    isActive,
    isLoading,
  } = useEngagement(accountId, {
    refreshInterval: 10000, // Poll every 10s for live updates
  });

  if (isLoading) return <EngagementSkeleton />;

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <h3>Growth Engine</h3>
        <button
          onClick={() => (isActive ? pause("Manual pause") : resume())}
          className={isActive ? "bg-yellow-500" : "bg-emerald-500"}
        >
          {isActive ? "Pause" : "Resume"}
        </button>
      </div>

      {/* Today's engagement stats */}
      <div className="grid grid-cols-3 gap-4">
        <div>
          <p className="text-2xl font-bold">
            {stats.actions.likes.performed}/{stats.actions.likes.limit}
          </p>
          <p className="text-sm text-gray-500">Likes today</p>
        </div>
        <div>
          <p className="text-2xl font-bold">
            {stats.actions.follows.performed}/{stats.actions.follows.limit}
          </p>
          <p className="text-sm text-gray-500">Follows today</p>
        </div>
        <div>
          <p className="text-2xl font-bold">
            {(stats.conversion_rates.follow_to_follow_back * 100).toFixed(1)}%
          </p>
          <p className="text-sm text-gray-500">Follow-back rate</p>
        </div>
      </div>

      {/* Recent activity feed */}
      <div>
        <h4>Recent Activity</h4>
        {activity.map((act) => (
          <div key={act.id} className="flex items-center gap-3 py-2">
            <span className="text-sm">{act.type}</span>
            <span className="font-medium">@{act.target_username}</span>
            <span className="ml-auto text-xs text-gray-400">
              {new Date(act.created_at).toLocaleTimeString()}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

Pre-built components

Drop-in components with className overrides and render props.

FollowerGrowthChart

import { FollowerGrowthChart } from "@outfame/react";

<FollowerGrowthChart
  accountId="acc_7Gx2kLm9Qr"
  period="30d"
  height={320}
  showTrend          // Overlay trend line
  showAnnotations    // Mark milestones (1K, 5K, 10K, etc.)
  showTooltip        // Hover tooltips with daily breakdown
  colors={{
    primary: "#ec4899",   // Line color
    gradient: ["#ec489920", "transparent"],
    milestone: "#10b981",
  }}
  className="rounded-xl border"
/>

EngagementStats

import { EngagementStats } from "@outfame/react";

<EngagementStats
  accountId="acc_7Gx2kLm9Qr"
  layout="grid"         // "grid" | "list" | "compact"
  showConversionRates   // Display follow-back rates
  showQualityScores     // Show AI quality scores per action
  period="7d"
/>

TargetingPanel

import { TargetingPanel } from "@outfame/react";

<TargetingPanel
  accountId="acc_7Gx2kLm9Qr"
  editable             // Allow inline editing
  showSuggestions      // Show targeting recommendations
  onUpdate={(config) => console.log("Targeting updated:", config)}
/>

CampaignManager

import { CampaignManager } from "@outfame/react";

<CampaignManager
  accountId="acc_7Gx2kLm9Qr"
  showHistory          // Display past campaigns
  showSchedule         // Show upcoming engagement schedule
  allowPause           // Enable pause/resume controls
  onStatusChange={(status) => console.log("Campaign:", status)}
/>

Custom dashboard

Hooks and components combined into a working dashboard. Adapt to your design system.

import {
  OutfameProvider,
  useAccount,
  useAnalytics,
  useEngagement,
  FollowerGrowthChart,
  EngagementStats,
} from "@outfame/react";

function InstagramGrowthDashboard({ accountId }: { accountId: string }) {
  const { data: account } = useAccount(accountId);
  const { data: analytics } = useAnalytics(accountId, { period: "30d" });
  const { stats, isActive, pause, resume } = useEngagement(accountId);

  if (!account || !analytics) return <DashboardSkeleton />;

  return (
    <div className="mx-auto max-w-6xl space-y-8 p-8">
      {/* Account header */}
      <header className="flex items-center justify-between">
        <div className="flex items-center gap-4">
          <img
            src={account.avatar_url}
            alt={account.instagram_username}
            className="h-14 w-14 rounded-full"
          />
          <div>
            <h1 className="text-2xl font-bold">
              @{account.instagram_username}
            </h1>
            <p className="text-gray-500">
              {account.followers_count.toLocaleString()} followers
            </p>
          </div>
        </div>
        <button
          onClick={() => isActive ? pause() : resume()}
          className={`rounded-lg px-4 py-2 font-medium ${
            isActive
              ? "bg-emerald-50 text-emerald-700"
              : "bg-gray-100 text-gray-700"
          }`}
        >
          {isActive ? "Growing" : "Paused"}
        </button>
      </header>

      {/* Key metrics */}
      <div className="grid grid-cols-4 gap-6">
        <MetricCard
          label="Net Growth"
          value={`+${analytics.net_growth.toLocaleString()}`}
          description="Followers gained"
        />
        <MetricCard
          label="Engagement Rate"
          value={`${analytics.engagement_rate}%`}
          description="Avg across all content"
        />
        <MetricCard
          label="Quality Score"
          value={`${analytics.audience_quality.score}/100`}
          description="Follower quality score"
        />
        <MetricCard
          label="Follow-back Rate"
          value={`${(stats.conversion_rates.follow_to_follow_back * 100).toFixed(1)}%`}
          description="Users who followed back"
        />
      </div>

      {/* Growth chart */}
      <section className="rounded-2xl border p-6">
        <h2 className="mb-4 text-lg font-semibold">Follower Growth</h2>
        <FollowerGrowthChart
          accountId={accountId}
          period="30d"
          height={360}
          showTrend
          showAnnotations
        />
      </section>

      {/* Engagement breakdown */}
      <section className="rounded-2xl border p-6">
        <h2 className="mb-4 text-lg font-semibold">Engagement Overview</h2>
        <EngagementStats
          accountId={accountId}
          layout="grid"
          showConversionRates
          period="30d"
        />
      </section>
    </div>
  );
}

function MetricCard({ label, value, description }: {
  label: string;
  value: string;
  description: string;
}) {
  return (
    <div className="rounded-xl border p-5">
      <p className="text-sm text-gray-500">{label}</p>
      <p className="mt-1 text-3xl font-bold">{value}</p>
      <p className="mt-1 text-xs text-gray-400">{description}</p>
    </div>
  );
}

// Wrap with provider at your app root
export default function App() {
  return (
    <OutfameProvider apiKey="sk_live_your_api_key">
      <InstagramGrowthDashboard accountId="acc_7Gx2kLm9Qr" />
    </OutfameProvider>
  );
}

TypeScript support

Every hook and component is typed. All types are exported.

import type {
  Account,
  AnalyticsOverview,
  GrowthDataPoint,
  TargetingConfig,
  TargetingSuggestions,
  EngagementStats,
  EngagementActivity,
  AudienceQuality,
  CampaignStatus,
  OutfameError,
} from "@outfame/react";

// All hooks return typed data
const { data } = useAccount("acc_7Gx2kLm9Qr");
//     ^? Account | undefined

const { data: analytics } = useAnalytics("acc_7Gx2kLm9Qr", { period: "30d" });
//     ^? AnalyticsOverview | undefined

// Component props are fully typed
<FollowerGrowthChart
  accountId="acc_7Gx2kLm9Qr"
  period="30d"       // "7d" | "30d" | "90d" | "1y" | "custom"
  granularity="daily" // "hourly" | "daily" | "weekly" | "monthly"
  height={320}        // number
  showTrend           // boolean
/>

Generic hooks

import { useOutfame } from "@outfame/react";

// Custom typed request
interface CustomMetrics {
  totalReach: number;
  viralPosts: number;
  topHashtags: string[];
}

const { data } = useOutfame<CustomMetrics>(
  `/accounts/acc_7Gx2kLm9Qr/custom-metrics`,
  { period: "30d" }
);
// data is typed as CustomMetrics | undefined

State management

Uses an internal SWR-like cache. Works alongside Redux, Zustand, Jotai, TanStack Query, or plain Context.

LibraryCompatibilityPattern
Redux / Redux ToolkitFullUse hooks inside components, dispatch to store as needed
ZustandFullSync hook data to Zustand store via useEffect
React ContextFullNest OutfameProvider inside your context providers
JotaiFullDerive atoms from hook return values
TanStack QueryFullUse outfame.sdk directly inside queryFn

Zustand example

import { create } from "zustand";
import { useAnalytics } from "@outfame/react";
import { useEffect } from "react";

interface GrowthStore {
  netGrowth: number;
  engagementRate: number;
  setMetrics: (netGrowth: number, engagementRate: number) => void;
}

const useGrowthStore = create<GrowthStore>((set) => ({
  netGrowth: 0,
  engagementRate: 0,
  setMetrics: (netGrowth, engagementRate) =>
    set({ netGrowth, engagementRate }),
}));

// Sync Outfame data into Zustand
function useGrowthSync(accountId: string) {
  const { data } = useAnalytics(accountId, { period: "30d" });
  const setMetrics = useGrowthStore((s) => s.setMetrics);

  useEffect(() => {
    if (data) {
      setMetrics(data.net_growth, data.engagement_rate);
    }
  }, [data, setMetrics]);
}

Configuration

OptionTypeDefaultDescription
apiKeystringYour Outfame API key or proxy token.
options.cacheTtlnumber60000Cache time-to-live in milliseconds.
options.revalidateOnFocusbooleantrueRefetch when window regains focus.
options.realtimebooleanfalseEnable WebSocket for live follower updates.
options.baseUrlstringhttps://api.outfame.com/v1API base URL. Override for proxy setups.
options.errorRetryCountnumber3Number of retries on transient errors.

Next stepsNext.js integration for SSR | Growth guide