Skip to main content

TypeScript Types

The Glood Hydrogen SDK is built with TypeScript-first design, providing comprehensive type definitions for all interfaces, configurations, and data structures.

Core Configuration Types

GloodConfig

Main configuration interface for creating a Glood client.
interface GloodConfig {
  /** Glood API key for authentication */
  apiKey: string;

  /** Your Shopify domain (e.g., 'store-name.myshopify.com') */
  myShopifyDomain: string;

  /** App-specific configurations (optional - uses defaults if not provided) */
  apps?: {
    recommendations?: RecommendationsAppConfig;
    search?: SearchAppConfig;
    wishlist?: WishlistAppConfig;
  };

  /** Enable debug logging in development */
  debug?: boolean;

  /** Additional settings object */
  settings?: Record<string, any>;
}
Usage:
const config: GloodConfig = {
  apiKey: process.env.GLOOD_API_KEY!,
  myShopifyDomain: 'your-store.myshopify.com',
  debug: true,
};

PixelConfig

Configuration for pixel tracking per app.
interface PixelConfig {
  /** Enable/disable pixel tracking for this app */
  enabled: boolean;

  /** Pixel tracking endpoint */
  endpoint: string;

  /** Required consent types for pixel tracking */
  consent: readonly ConsentType[];
}
Usage:
const pixelConfig: PixelConfig = {
  enabled: true,
  endpoint: 'https://events.glood.ai',
  consent: ['analytics', 'marketing'],
};

App Configuration Types

RecommendationsAppConfig

Configuration specific to the recommendations app.
interface RecommendationsAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

SearchAppConfig

Configuration specific to the search app.
interface SearchAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

WishlistAppConfig

Configuration specific to the wishlist app.
interface WishlistAppConfig {
  /** Main app endpoint for features and API calls */
  endpoint: string;

  /** Pixel tracking configuration */
  pixel: PixelConfig;

  /** Events this app should subscribe to (defaults to all events if not specified) */
  subscribedEvents?: EventType[];
}

Client & App Types

GloodClient

The main client interface returned by createGlood().
interface GloodClient {
  /** Configuration used to create this client */
  config: GloodConfig;

  /** Debug mode enabled */
  debug: boolean;

  /** Registered apps */
  apps: Map<AppName, GloodApp>;

  /** Get all enabled apps */
  getEnabledApps(): GloodApp[];

  /** Get specific app by name */
  getApp(name: AppName): GloodApp | undefined;

  /** Add an app module to the client */
  use(appModuleOrFactory: GloodAppModule | ((config?: any) => GloodAppModule)): GloodClient;
}

GloodApp

Interface representing an individual app instance.
interface GloodApp {
  /** App name */
  name: AppName;

  /** Main app endpoint for features */
  endpoint: string;

  /** Pixel configuration */
  pixel: PixelConfig;

  /** Events this app subscribes to */
  subscribedEvents: EventType[];

  /** Analytics instance from Hydrogen useAnalytics hook */
  analytics?: any;

  /** Handle an analytics event */
  handleEvent(eventType: EventType, eventData: any, client: GloodClient): void;

  /** Set analytics instance on the app */
  setAnalytics(analytics: any): void;

  /** Update subscribed events for this app */
  setSubscribedEvents(events: EventType[]): void;
}

GloodAppModule

Function type for app module factories.
interface GloodAppModule {
  /** Create app instance with optional custom configuration */
  (): GloodApp;
}
Usage:
// App module functions return GloodAppModule
const recommendationsModule: GloodAppModule = recommendations();
const searchModule: GloodAppModule = search();
const wishlistModule: GloodAppModule = wishlist();

React Component Types

GloodProviderProps

Props for the GloodProvider React component.
interface GloodProviderProps {
  /** Glood client instance */
  client: GloodClient;

  /** Child components to wrap */
  children: React.ReactNode;

  /** Optional analytics instance (for advanced usage) */
  analytics?: any;
}
Usage:
function App() {
  return (
    <GloodProvider client={glood} loaderData={data}>
      <YourApp />
    </GloodProvider>
  );
}

Analytics Event Data Types

PageViewData

Data structure for page view events.
interface PageViewData {
  url: string;
  title?: string;
  referrer?: string;
  timestamp: number;
}

ProductViewData

Data structure for product view events.
interface ProductViewData {
  productId: string;
  productHandle: string;
  productTitle: string;
  productPrice: number;
  productVendor?: string;
  productType?: string;
  currency: string;
  timestamp: number;
}

SearchData

Data structure for search events.
interface SearchData {
  query: string;
  resultsCount: number;
  timestamp: number;
}

CollectionViewData

Data structure for collection view events.
interface CollectionViewData {
  collectionId: string;
  collectionHandle: string;
  collectionTitle: string;
  timestamp: number;
}

CartViewData

Data structure for cart view events.
interface CartViewData {
  cartId: string;
  totalPrice: number;
  itemCount: number;
  timestamp: number;
}

Recommendations API Types

GetSectionsParams

Parameters for fetching recommendation sections — used by both useRecommendations() and fetchRecommendationSections().
interface GetSectionsParams {
  /** Page type the visitor is on */
  pageType: PageType;

  /** Full URL of the current page (defaults to window.location.href in the browser) */
  pageUrl?: string;

  /** Locale code, e.g. 'en-US' (defaults to navigator.language in the browser) */
  locale?: string;

  /** Numeric Shopify product id (not GID) — required for product page recommendations */
  productId?: string | number;

  /** Numeric product ids currently in the cart */
  cartProductIds?: Array<string | number>;

  /** Specific Glood section ids to fetch (empty = all enabled sections for the page) */
  sections?: number[];

  /** Glood client id (defaults to the _glood_client_id cookie in the browser) */
  clientId?: string;

  /** Logged-in user id */
  userId?: string;

  /** Shopify customer id */
  customerId?: string;

  /** Market id for multi-market shops */
  market?: string;

  /** Currency code */
  currency?: string;

  /** Cart total value */
  cartValue?: string;

  /** Numeric collection id (for collection pages) */
  collection?: number;

  /** Query string used for experience assignment */
  qs?: string;

  /** Include disabled sections (preview mode) */
  preview?: boolean;
}
Usage:
const params: GetSectionsParams = {
  pageType: 'product_page',
  productId: '8977367564515',
};

SectionsResponse

Full response from the sections API.
interface SectionsResponse {
  /** Unique id for this request — pass to attribution events */
  request_id: string;

  /** Sections with full product data */
  sections: RecommendationSection[];

  /** Current product details (product pages), or null */
  product: Record<string, any> | null;

  /** Shopify storefront access token from the shop config */
  token: string | null;

  /** Shop configuration (currency, money format, integrations, ...) */
  config: Record<string, any>;

  /** Assigned A/B experience id — persisted to localStorage automatically */
  experience: string | null;

  /** Unique id for this visit */
  visit_id: string | null;
}

RecommendationSection

A recommendation section configured in the Glood dashboard, served with its products.
interface RecommendationSection {
  /** Glood section id */
  id: number;

  /** Serve id used to attribute glood:section:* events to this render */
  section_serve_id: string;

  /** Page type this section was served for */
  page_type: string;

  /** A/B experience this section belongs to */
  experience_id: string | null;

  /** Layout, e.g. 'horizontal_grid', 'carousel' */
  layout: string;

  /** Placement location configured in the dashboard */
  location: string;

  /** Recommendation type, e.g. 'bestsellers', 'similar_products', 'bought_together' */
  type: string;

  /** Position among sections on the page */
  position: number;

  /** Translated section title */
  title: string;

  /** Extra section settings */
  extra: Record<string, any>;

  /** Discount configuration for this section */
  discount_config: Record<string, any> | null;

  /** Whether to show discount labels */
  show_discount_label: boolean;

  /** Title translations */
  translations: Record<string, any> | null;

  /** Recommended products with full data */
  products: SectionProduct[];

  /** Pagination cursor (null when not paginated) */
  cursor: string | null;

  /** Whether more products are available */
  hasMore: boolean;
}

SectionProduct

A recommended product with complete display data.
interface SectionProduct {
  /** Numeric Shopify product id */
  product_id: number;

  title: string;
  handle: string;
  vendor?: string;
  product_type?: string;

  /** Comma-separated tag list */
  tags?: string;

  /** Minimum price across variants */
  price: number | null;

  /** Compare-at price (null when not on sale) */
  compare_at_price: number | null;

  /** Featured image */
  image?: { url?: string } | null;

  /** Product options (Size, Color, ...) */
  options: SectionProductOption[];

  /** All variants */
  variants: SectionProductVariant[];

  metafields?: Array<{ namespace: string; key: string; value: string }>;
}

SectionProductVariant

interface SectionProductVariant {
  /** Numeric Shopify variant id */
  variant_id: number;

  title: string;
  display_name?: string;
  position?: number;
  sku?: string;

  /** Selected option values, e.g. [{ name: 'Size', value: 'S' }] */
  selected_options: Array<{ name: string; value: string }>;

  price: number | string | null;
  compare_at_price: number | string | null;
  image?: { url?: string } | null;
}

SectionProductOption

interface SectionProductOption {
  id: number;
  name: string;
  values: string[];
  position: number;
}

SectionTrack

Attribution payload linking a glood:section:* event to a specific section render.
interface SectionTrack {
  /** Glood section id (as a string) */
  section?: string;

  /** section_serve_id from the sections response */
  sectionServeId?: string;

  /** request_id from the sections response */
  requestId?: string;

  /** Page type where the interaction happened */
  page?: string;

  /** Context product (e.g. the PDP product the section rendered on) */
  parent?: { productId?: string; variantId?: string };

  /** Products involved in the interaction */
  products?: SectionTrackProduct[];
}

interface SectionTrackProduct {
  productId: string;
  variantId?: string;
  quantity?: number;
}

FetchSectionsOptions

Options for fetchRecommendationSections().
interface FetchSectionsOptions {
  /** Glood storefront token (same value as GloodConfig.apiKey) */
  apiKey: string;

  /** Shop domain, e.g. 'store-name.myshopify.com' */
  myShopifyDomain: string;

  /** Recommendations endpoint override (defaults to https://storefront.glood.ai) */
  endpoint?: string;

  /** Log request/response details */
  debug?: boolean;
}

GloodApiError

Error thrown when the sections API responds with a non-2xx status.
class GloodApiError extends Error {
  /** HTTP status code */
  readonly status: number;

  /** Parsed JSON error body */
  readonly body: unknown;
}
Usage:
import { GloodApiError } from '@glood/hydrogen';

if (error instanceof GloodApiError) {
  console.error(error.status, error.body);
}

Pixel System Types

PixelEvent

Structure for pixel events in the transmission queue.
interface PixelEvent {
  endpoint: string;

  /** Shop domain sent as the x-shop-myshopify-domain header (required by the ingestion API) */
  shopDomain: string;

  data: Record<string, any>;
}

PixelPayload

Complete pixel payload sent to Glood endpoints.
interface PixelPayload {
  events: Record<string, any>[];
  apiKey: string;
  shopDomain: string;
  timestamp: number;
}

Constant Types

AppName

Union type for available app names.
type AppName = 'recommendations' | 'search' | 'wishlist';
Usage:
const appName: AppName = 'recommendations'; // ✅ Valid
const invalidName: AppName = 'invalid'; // ❌ TypeScript error

EventType

Union type for all supported analytics events.
type EventType =
  | 'page_viewed'
  | 'product_viewed'
  | 'collection_viewed'
  | 'cart_viewed'
  | 'search_viewed'
  | 'search_submitted'
  | 'custom_promotion_viewed'
  | 'product_added_to_cart'
  | 'product_removed_from_cart';
Usage:
const event: EventType = 'product_viewed'; // ✅ Valid
const invalidEvent: EventType = 'invalid_event'; // ❌ TypeScript error

ConsentType

Union type for customer privacy consent types.
type ConsentType =
  | 'analytics'
  | 'marketing'
  | 'preferences'
  | 'sale_of_data';
Usage:
const consent: ConsentType[] = ['analytics', 'marketing']; // ✅ Valid
const invalidConsent: ConsentType[] = ['invalid']; // ❌ TypeScript error

PageType

Union type of page types accepted by the sections API.
type PageType =
  | 'product_page'
  | 'collection'
  | 'home'
  | 'cart'
  | 'order_confirm'
  | 'other'
  | 'blog'
  | 'ajax_cart'
  | '404'
  | 'checkout'
  | 'returns';
The PAGE_TYPES constant exports the same list as a runtime array.

GloodSectionEventName

Union type of the custom attribution event names.
type GloodSectionEventName =
  | 'glood:section:render'
  | 'glood:section:view'
  | 'glood:section:click'
  | 'glood:section:add_to_cart';
The SECTION_EVENT_NAMES constant exports the same list as a runtime array.

Type Guards and Utilities

Type Guard Functions

Helper functions to check types at runtime:
// Check if value is a valid app name
function isAppName(value: string): value is AppName {
  return ['recommendations', 'search', 'wishlist'].includes(value);
}

// Check if value is a valid event type
function isEventType(value: string): value is EventType {
  return [
    'page_viewed',
    'product_viewed',
    'collection_viewed',
    'cart_viewed',
    'search_viewed',
    'search_submitted',
    'custom_promotion_viewed',
    'product_added_to_cart',
    'product_removed_from_cart'
  ].includes(value);
}

// Check if value is a valid consent type
function isConsentType(value: string): value is ConsentType {
  return ['analytics', 'marketing', 'preferences', 'sale_of_data'].includes(value);
}

Utility Types

Common utility types for working with the SDK:
// Extract app names from client
type EnabledApps<T extends GloodClient> = T['apps'] extends Map<infer K, any> ? K : never;

// Get app config type by name
type AppConfigType<T extends AppName> =
  T extends 'recommendations' ? RecommendationsAppConfig :
  T extends 'search' ? SearchAppConfig :
  T extends 'wishlist' ? WishlistAppConfig :
  never;

// Partial app configuration for overrides
type PartialAppConfig<T extends AppName> = Partial<AppConfigType<T>>;

Advanced TypeScript Usage

Generic App Factory

Create type-safe app factories:
function createAppFactory<T extends AppName>(
  appName: T,
  defaultConfig: AppConfigType<T>
) {
  return (config?: PartialAppConfig<T>): GloodAppModule => {
    return () => {
      // Implementation
      return {} as GloodApp;
    };
  };
}

// Usage with full type safety
const recommendationsFactory = createAppFactory('recommendations', {
  endpoint: 'https://storefront.glood.ai',
  pixel: {
    enabled: true,
    endpoint: 'https://events.glood.ai',
    consent: ['analytics', 'marketing'] as const,
  },
});

Type-Safe Configuration Builder

Build configurations with compile-time validation:
class GloodConfigBuilder {
  private config: Partial<GloodConfig> = {};

  apiKey(key: string): this {
    this.config.apiKey = key;
    return this;
  }

  shopifyDomain(domain: string): this {
    this.config.myShopifyDomain = domain;
    return this;
  }

  app<T extends AppName>(
    name: T,
    config: AppConfigType<T>
  ): this {
    if (!this.config.apps) {
      this.config.apps = {};
    }
    (this.config.apps as any)[name] = config;
    return this;
  }

  debug(enabled: boolean = true): this {
    this.config.debug = enabled;
    return this;
  }

  build(): GloodConfig {
    if (!this.config.apiKey) {
      throw new Error('API key is required');
    }
    if (!this.config.myShopifyDomain) {
      throw new Error('Shopify domain is required');
    }
    return this.config as GloodConfig;
  }
}

// Usage
const config = new GloodConfigBuilder()
  .apiKey(process.env.GLOOD_API_KEY!)
  .shopifyDomain('store.myshopify.com')
  .app('recommendations', {
    endpoint: 'https://storefront.glood.ai',
    pixel: {
      enabled: true,
      endpoint: 'https://events.glood.ai',
      consent: ['analytics'],
    },
  })
  .debug(true)
  .build();

Event Handler Typing

Type-safe event handlers:
type EventHandler<T extends EventType> = (
  eventData: T extends 'product_viewed' ? ProductViewData :
              T extends 'search_submitted' ? SearchData :
              T extends 'cart_viewed' ? CartViewData :
              Record<string, any>
) => void;

function createEventHandler<T extends EventType>(
  eventType: T,
  handler: EventHandler<T>
) {
  return (eventData: any) => {
    // Runtime validation could be added here
    handler(eventData);
  };
}

// Usage with type safety
const productViewHandler = createEventHandler('product_viewed', (data) => {
  // data is typed as ProductViewData
  console.log(`Product viewed: ${data.productTitle}`);
});

Type Imports

Import specific types as needed:
// Import all types
import type {
  GloodConfig,
  GloodClient,
  GloodApp,
  AppName,
  EventType,
  ConsentType,
  PixelConfig,
} from '@glood/hydrogen';

// Import specific app config types
import type {
  RecommendationsAppConfig,
  SearchAppConfig,
  WishlistAppConfig,
} from '@glood/hydrogen';

// Import event data types
import type {
  PageViewData,
  ProductViewData,
  SearchData,
  CartViewData,
} from '@glood/hydrogen';

// Import React component types
import type {
  GloodProviderProps,
} from '@glood/hydrogen';

// Import recommendations API types
import type {
  GetSectionsParams,
  SectionsResponse,
  RecommendationSection,
  SectionProduct,
  SectionProductVariant,
  SectionProductOption,
  SectionTrack,
  SectionTrackProduct,
  FetchSectionsOptions,
  UseRecommendationsOptions,
  UseRecommendationsResult,
  PageType,
  GloodSectionEventName,
} from '@glood/hydrogen';

Common TypeScript Patterns

Optional Configuration

Make app configurations optional with defaults:
interface OptionalGloodConfig {
  apiKey: string;
  myShopifyDomain: string;
  apps?: Partial<{
    recommendations: Partial<RecommendationsAppConfig>;
    search: Partial<SearchAppConfig>;
    wishlist: Partial<WishlistAppConfig>;
  }>;
  debug?: boolean;
}

function createGloodWithDefaults(config: OptionalGloodConfig): GloodClient {
  const fullConfig: GloodConfig = {
    ...config,
    apps: {
      recommendations: {
        endpoint: 'https://storefront.glood.ai',
        pixel: {
          enabled: true,
          endpoint: 'https://events.glood.ai',
          consent: ['analytics', 'marketing'],
        },
        ...config.apps?.recommendations,
      },
      // ... other app defaults
    },
  };

  return createGlood(fullConfig);
}

Conditional App Configuration

Configure apps based on conditions:
type ConditionalConfig<T extends boolean> = T extends true
  ? Required<GloodConfig>
  : Partial<GloodConfig>;

function createConditionalGlood<T extends boolean>(
  isProduction: T,
  config: ConditionalConfig<T>
): GloodClient {
  if (isProduction) {
    // Production requires full configuration
    return createGlood(config as Required<GloodConfig>);
  } else {
    // Development allows partial configuration
    return createGlood({
      ...config,
      debug: true,
    } as GloodConfig);
  }
}

Best Practices

1. Use Strict Types

Enable strict TypeScript settings:
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

2. Type Imports

Use type-only imports when possible:
// ✅ Good - Type-only import
import type { GloodConfig } from '@glood/hydrogen';

// ❌ Avoid - Runtime import for types
import { GloodConfig } from '@glood/hydrogen';

3. Const Assertions

Use const assertions for literal types:
// ✅ Good - Const assertion preserves literal types
const consent = ['analytics', 'marketing'] as const;

// ❌ Avoid - Loses literal type information
const consent: ConsentType[] = ['analytics', 'marketing'];

4. Generic Constraints

Use generic constraints for type safety:
function configureApp<T extends AppName>(
  name: T,
  config: AppConfigType<T>
): void {
  // Implementation
}

// Usage is fully type-safe
configureApp('recommendations', {
  endpoint: 'https://storefront.glood.ai',
  pixel: {
    enabled: true,
    endpoint: 'https://events.glood.ai',
    consent: ['analytics', 'marketing'],
  },
});

See Also