> ## Documentation Index
> Fetch the complete documentation index at: https://docs.glood.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# React Components

> Complete reference for GloodProvider component and useGloodAnalytics hook

# React Components

The SDK provides React components and hooks for seamless integration with your Hydrogen application.

## GloodProvider

A React context provider that automatically subscribes to Shopify Analytics events and manages pixel tracking across all registered Glood apps.

### Signature

```typescript theme={null}
function GloodProvider({
  client,
  children
}: GloodProviderProps): React.ReactElement
```

### Props

| Prop       | Type              | Required | Description                                        |
| ---------- | ----------------- | -------- | -------------------------------------------------- |
| `client`   | `GloodClient`     | Yes      | Glood client instance created with `createGlood()` |
| `children` | `React.ReactNode` | Yes      | Child components to wrap                           |

### Basic Usage

```tsx theme={null}
import { Analytics } from '@shopify/hydrogen';
import { GloodProvider, createGlood } from '@glood/hydrogen';
import { recommendations, search, wishlist } from '@glood/hydrogen';

const glood = createGlood({
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
})
  .use(recommendations())
  .use(search())
  .use(wishlist());

export default function App() {
  return (
    <Analytics>
      <GloodProvider client={glood} loaderData={data}>
        <Outlet />
      </GloodProvider>
    </Analytics>
  );
}
```

### How It Works

The `GloodProvider` component:

1. **Creates React Context** - Provides the Glood client to all child components
2. **Subscribes to Analytics** - Uses Hydrogen's `useAnalytics()` hook to receive events
3. **Distributes Events** - Routes events to interested apps based on their subscriptions
4. **Checks Consent** - Verifies customer privacy permissions before sending pixels
5. **Handles Errors** - Provides comprehensive error handling and debug logging

### Event Subscription Flow

```mermaid theme={null}
graph TD
    A[Shopify Analytics] --> B[GloodProvider]
    B --> C[Event Distribution]
    C --> D[Consent Check]
    D --> E[Pixel Transmission]
    E --> F[Glood Endpoints]
```

### Error Handling

The provider includes comprehensive error handling:

```tsx theme={null}
// Invalid client handling
<GloodProvider client={null}>
  <App />
</GloodProvider>
// Logs: "[Glood] GloodProvider: client is required"
// Renders children without Glood functionality

// Debug mode error logging
const glood = createGlood({
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
  debug: true, // Enable detailed error logging
});

<GloodProvider client={glood} loaderData={data}>
  <App />
</GloodProvider>
```

### Server-Side Rendering

The provider automatically handles SSR:

```tsx theme={null}
// Only runs on client-side
useEffect(() => {
  if (typeof window === 'undefined' || !analytics?.customerPrivacy) {
    if (debug) {
      console.log('[Glood Debug] Skipping analytics setup: not in browser');
    }
    return;
  }
  // Setup analytics subscriptions
}, [clientConfig, analytics]);
```

### Context Integration

The provider creates a React Context to share the client:

```tsx theme={null}
const GloodContext = createContext<GloodClient | null>(null);

export function GloodProvider({ client, children }) {
  // ... analytics setup

  return (
    <GloodContext.Provider value={client}>
      {children}
    </GloodContext.Provider>
  );
}
```

## useGloodAnalytics

A React hook that provides access to the Glood client from context.

### Signature

```typescript theme={null}
function useGloodAnalytics(): GloodClient | null
```

### Returns

| Type                  | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `GloodClient \| null` | The Glood client instance or `null` if used outside provider |

### Usage

```tsx theme={null}
import { useGloodAnalytics } from '@glood/hydrogen';

function MyComponent() {
  const glood = useGloodAnalytics();

  if (!glood) {
    // Component used outside GloodProvider
    return <div>Glood not available</div>;
  }

  // Access client properties
  const isDebugMode = glood.debug;
  const enabledApps = glood.getEnabledApps();

  return (
    <div>
      <p>Debug mode: {isDebugMode ? 'On' : 'Off'}</p>
      <p>Enabled apps: {enabledApps.map(app => app.name).join(', ')}</p>
    </div>
  );
}
```

### Custom Integrations

Use the hook for custom integrations with Glood apps:

```tsx theme={null}
import { useGloodAnalytics } from '@glood/hydrogen';

function CustomRecommendations() {
  const glood = useGloodAnalytics();
  const [recommendations, setRecommendations] = useState([]);

  useEffect(() => {
    if (!glood) return;

    const recommendationsApp = glood.getApp('recommendations');
    if (!recommendationsApp) return;

    // Custom API call to recommendations endpoint
    fetch(`${recommendationsApp.endpoint}/api/recommendations`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${glood.config.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        shopDomain: glood.config.myShopifyDomain,
        // ... other parameters
      }),
    })
      .then(response => response.json())
      .then(data => setRecommendations(data.recommendations))
      .catch(error => console.error('Recommendations error:', error));
  }, [glood]);

  return (
    <div>
      {recommendations.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
}
```

### Conditional Rendering

Use the hook for conditional rendering based on Glood availability:

```tsx theme={null}
import { useGloodAnalytics } from '@glood/hydrogen';

function EnhancedSearchBox() {
  const glood = useGloodAnalytics();
  const hasSearchApp = glood?.getApp('search');

  if (hasSearchApp) {
    return <GloodSearchBox />;
  }

  return <StandardSearchBox />;
}
```

## Provider Placement

### Correct Placement

The `GloodProvider` must be placed correctly in your component tree:

```tsx theme={null}
// ✅ Correct - Inside Analytics, wrapping application routes
import { Analytics } from '@shopify/hydrogen';

export default function App() {
  return (
    <html>
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        <Analytics>
          <GloodProvider client={glood} loaderData={data}>
            <Layout>
              <Outlet />
            </Layout>
          </GloodProvider>
        </Analytics>
        <Scripts />
      </body>
    </html>
  );
}
```

### Incorrect Placement

```tsx theme={null}
// ❌ Incorrect - Outside Analytics component
export default function App() {
  return (
    <GloodProvider client={glood} loaderData={data}>
      <Analytics>
        <Outlet />
      </Analytics>
    </GloodProvider>
  );
}

// ❌ Incorrect - Inside individual routes
export default function ProductPage() {
  return (
    <GloodProvider client={glood} loaderData={data}>
      <ProductDetails />
    </GloodProvider>
  );
}
```

## Debug Logging

Enable debug mode to see detailed component behavior:

```tsx theme={null}
const glood = createGlood({
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
  debug: process.env.NODE_ENV === 'development',
});

<GloodProvider client={glood} loaderData={data}>
  <App />
</GloodProvider>
```

Debug logs include:

```
[Glood Debug] Setting up event subscriptions for apps: ['recommendations', 'search', 'wishlist']
[Glood Debug] Set analytics instance on recommendations app
[Glood Debug] App recommendations subscribes to events: ['page_viewed', 'product_viewed', ...]
[Glood Debug] All unique event types: ['page_viewed', 'product_viewed', 'search_submitted', ...]
[Glood Debug] Setting up centralized subscription for page_viewed
[Glood Debug] Received page_viewed event, distributing to interested apps
[Glood Debug] Apps interested in page_viewed: ['recommendations', 'search', 'wishlist']
[Glood Debug] Processing page_viewed event for recommendations: { url: '/products/shirt', ... }
[Glood Debug] Consent granted for recommendations, processing event
```

## Performance Considerations

### Memoization

The provider uses React's `useMemo` to prevent unnecessary re-renders:

```tsx theme={null}
const clientConfig = useMemo(() => ({
  debug: client.debug,
  enabledApps: client.getEnabledApps(),
  appsKeys: Array.from(client.apps.keys())
}), [client.debug, client.apps]);
```

### Event Deduplication

Events are subscribed to only once per event type, regardless of how many apps are interested:

```tsx theme={null}
// Subscribe once per event type
allEventTypes.forEach((eventType: EventType) => {
  subscribe(eventType, (eventData: any) => {
    // Distribute to all interested apps
    const interestedApps = enabledAppsWithPixel.filter(app =>
      app.subscribedEvents.includes(eventType)
    );

    interestedApps.forEach(app => {
      app.handleEvent(eventType, eventData, client);
    });
  });
});
```

### Lazy Loading

Analytics setup is deferred to prevent blocking:

```tsx theme={null}
useEffect(() => {
  const timer = setTimeout(() => {
    // Setup analytics subscriptions
  }, 0);

  return () => clearTimeout(timer);
}, [clientConfig, analytics]);
```

## Error Scenarios

### Missing Analytics

```tsx theme={null}
// Hydrogen analytics not available
if (!analytics?.customerPrivacy) {
  if (debug) {
    console.log('[Glood Debug] Skipping analytics setup: analytics not available');
  }
  return;
}
```

### Network Errors

```tsx theme={null}
// Pixel transmission errors are handled gracefully
try {
  app.handleEvent(eventType, eventData, client);
} catch (error) {
  console.error('[Glood] Error processing event:', error);
  if (debug) {
    console.error('[Glood Debug] Event data:', eventData);
  }
}
```

### Consent Denial

```tsx theme={null}
// Events are not processed if consent is not granted
if (checkConsent(app.pixel.consent, canTrack, analytics)) {
  app.handleEvent(eventType, eventData, client);
} else {
  if (debug) {
    console.log(`[Glood Debug] Consent not granted for ${app.name}, skipping event`);
  }
}
```

## Best Practices

### 1. Single Provider Instance

Use only one `GloodProvider` at the root of your application:

```tsx theme={null}
// ✅ Good - Single provider at root
<GloodProvider client={glood} loaderData={data}>
  <App />
</GloodProvider>

// ❌ Bad - Multiple providers
<GloodProvider client={glood1}>
  <Header />
</GloodProvider>
<GloodProvider client={glood2}>
  <Main />
</GloodProvider>
```

### 2. Client Stability

Create the client outside of the component to prevent recreating:

```tsx theme={null}
// ✅ Good - Client created once
const glood = createGlood(config).use(recommendations());

export default function App() {
  return (
    <GloodProvider client={glood} loaderData={data}>
      <Outlet />
    </GloodProvider>
  );
}

// ❌ Bad - Client recreated on every render
export default function App() {
  const glood = createGlood(config).use(recommendations());

  return (
    <GloodProvider client={glood} loaderData={data}>
      <Outlet />
    </GloodProvider>
  );
}
```

### 3. Conditional Hook Usage

Always check for null when using the hook:

```tsx theme={null}
function MyComponent() {
  const glood = useGloodAnalytics();

  // ✅ Good - Check for null
  if (!glood) {
    return <FallbackComponent />;
  }

  // Use glood safely
  const apps = glood.getEnabledApps();
}
```

### 4. Error Boundaries

Wrap the provider in error boundaries for production:

```tsx theme={null}
import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error }) {
  return (
    <div>
      <h2>Glood Error</h2>
      <pre>{error.message}</pre>
    </div>
  );
}

export default function App() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <Analytics>
        <GloodProvider client={glood} loaderData={data}>
          <Outlet />
        </GloodProvider>
      </Analytics>
    </ErrorBoundary>
  );
}
```

## See Also

* [Client API](/for-developers/glood-hydrogen-sdk/api-reference/client) - createGlood() and GloodClient
* [App Modules](/for-developers/glood-hydrogen-sdk/api-reference/app-modules) - App configuration and usage
* [Event System](/for-developers/glood-hydrogen-sdk/api-reference/event-system) - Event tracking and pixel transmission
* [Examples](/for-developers/glood-hydrogen-sdk/examples/context-usage) - Context usage patterns
