Hydrogen SDK: Implementation Patterns¶
Beta SDK
These SDKs are currently in beta. APIs may change before stable release.
The Hydrogen SDK supports both server-side and client-side rendering patterns, giving you flexibility in how you implement Rebuy features.
Server-Side vs Client-Side Rendering¶
Server-Side Rendering (Recommended)¶
Server-side rendering is recommended for most use cases, including product recommendations, top sellers, and cart-based widgets. It offers better SEO, faster initial page loads, and built-in cart reactivity through Remix loaders.
Use Server-Side Rendering for:
- Most recommendation widgets
- SEO-critical content
- Fast initial page loads
Client-Side Rendering¶
Client-side rendering is necessary for features that rely on browser-specific data, such as localStorage. The primary use case is for "Recently Viewed" products.
Use Client-Side Rendering for:
- Recently Viewed products
- Features requiring real-time user interaction in the browser
Data Fetching Approaches¶
There are two main approaches for fetching recommendation data: Direct API calls and Data Sources.
Direct API¶
The Direct API provides a straightforward way to get recommendations with minimal setup. It's suitable for prototyping or for widgets where admin-level configuration is not required.
// Example: Get recommended products based on cart contents
const recommendations = await rebuy.sdk.products.getRecommended({
...rebuy.cartContext,
limit: 4,
});
Data Sources (Recommended for Production)¶
Data Sources are the recommended approach for production environments. They unlock the full power of the Rebuy platform, allowing you to use the Rebuy Admin to configure business logic, run A/B tests, and manage targeting rules without changing your storefront code.
For example, you can create a rule like: "IF customer is VIP AND cart total > $100 THEN show premium products."
A critical feature for cart-based widgets is the "Filter Input Products" setting in the Data Source configuration. When enabled, it automatically prevents items already in the cart from appearing in the recommendations.
// Example: Fetch from a Data Source, limiting the result to 4 products.
const recommendations = await rebuy.sdk.products.fetchFromDataSource(
243093, // Your Data Source ID from the Rebuy Admin
rebuy.cartContext,
{ limit: 4 } // Optional: Pass parameters like limit here
);
Enhancing Context with RebuyContextBuilder¶
For more precise targeting, the RebuyContextBuilder utility can be used with either Direct API calls or Data Sources to create the context object. It allows you to enrich the request with additional data, such as customer information, URL parameters, and geolocation.
Options that are specific to a single request, like limit, should be passed as the third argument to fetchFromDataSource.
const enhancedContext = new RebuyContextBuilder(rebuy.sdk)
.merge(rebuy.cartContext)
.withUrl(request.url)
.withCustomer(customer)
.build();
// Use the enhanced context and pass a limit
const recommendations = await rebuy.sdk.products.fetchFromDataSource(
243093,
enhancedContext,
{ limit: 4 }
);
When to use which approach:
| Scenario | Approach |
|---|---|
| Prototyping or simple needs | Direct API |
| Production, cart-based widgets, or dynamic business logic | Data Sources |
| Improved targeting | Add RebuyContextBuilder to either approach |
Server-Side Rendering & Cart Reactivity¶
The SDK is designed to work seamlessly with Hydrogen's server-centric architecture. Using getRebuyData in your loaders is the key feature of this SDK.
Using getRebuyData in Loaders¶
The getRebuyData helper function provides the Rebuy SDK instance and automatically enriched cart context for your Remix loaders.
// app/routes/($locale).products.$handle.tsx
import { getRebuyData, RebuyContextBuilder } from '@rebuy/hydrogen-sdk';
import { defer, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
export async function loader({ context, params, request }: LoaderFunctionArgs) {
// Get Rebuy SDK with automatically enriched context
const { rebuy } = await getRebuyData({ context, request });
// Option 1: Use the auto-generated context directly
const recommendations = await rebuy.sdk.products.fetchFromDataSource(
'pdp-recommendations',
{
...rebuy.cartContext, // Includes cart, URL, country, language automatically
shopify_product_ids: params.productId,
}
);
// Option 2: Enhance the context further with RebuyContextBuilder
const enhancedContext = new RebuyContextBuilder(rebuy.sdk)
.merge(rebuy.cartContext) // Start with auto-generated context
.withProduct({ id: product.id }) // Add current product
.withCustomer({ id: customer.id, tags: customer.tags }) // Add customer data
.build();
const personalizedRecs = await rebuy.sdk.products.fetchFromDataSource(
'personalized-recommendations',
enhancedContext
);
return defer({ recommendations, personalizedRecs });
}
Automatic Context Enrichment:
When you pass the request parameter to getRebuyData, it automatically extracts:
| Context | Source |
|---|---|
| Cart Context | cart_total, cart_item_count, shopify_product_ids, etc. |
| URL Context | url_path and url_params from the current request |
| Geolocation | country_code from Hydrogen's i18n configuration |
| Language | language from Hydrogen's i18n configuration |
How Cart Reactivity Works¶
- Cart Mutation: User adds/removes items via Hydrogen's
<CartForm>. - Automatic Reload: Remix automatically re-runs loaders after cart mutations.
- Fresh Context:
getRebuyDataprovides updated cart context. - New Recommendations: Rebuy API returns fresh, cart-aware recommendations.
- UI Updates: Your component re-renders with the new data.
This pattern provides optimal performance, SEO, and a reactive user experience without complex client-side state management.
Complete Server-Side Widget Example¶
Here's a minimal, complete example of a server-side widget implementation:
Component:
// app/components/ServerTopSellers.tsx
import type { Product } from '@rebuy/core-sdk';
interface ServerTopSellersProps {
products: Product[];
title?: string;
}
export function ServerTopSellers({
products,
title = 'Top Sellers'
}: ServerTopSellersProps) {
if (!products || products.length === 0) return null;
return (
<div className="top-sellers">
<h2>{title}</h2>
<div className="product-grid">
{products.map((product) => (
<div key={product.id} className="product-card">
<img src={product.image?.src} alt={product.title} />
<h3>{product.title}</h3>
<p>${product.variants?.[0]?.price}</p>
</div>
))}
</div>
</div>
);
}
Route:
// app/routes/($locale)._index.tsx
import { getRebuyData } from '@rebuy/hydrogen-sdk';
import { defer, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
import { useLoaderData } from 'react-router';
import { ServerTopSellers } from '~/components/ServerTopSellers';
export async function loader({ context, request }: LoaderFunctionArgs) {
const { rebuy } = await getRebuyData({ context, request });
// Fetch data on the server
const topSellers = await rebuy.sdk.products.getTopSellers({
limit: 5,
filter_oos: 'yes',
});
return defer({ topSellers });
}
export default function Homepage() {
const { topSellers } = useLoaderData<typeof loader>();
// Render with server-fetched data - no loading states needed!
return <ServerTopSellers products={topSellers} />;
}
Key Benefits of This Pattern:
- Products are in the initial HTML (view source to verify)
- No loading spinners or layout shifts
- SEO-friendly - search engines see the content
- Automatically updates when cart changes (cart reactivity)
Related¶
- Components & Hooks - Component reference for client-side widgets
- Data Sources - Understanding custom endpoints
- Troubleshooting - Debug mode and common issues