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.
Utilities
The SDK provides various utility functions for consent management, data transformation, browser context handling, and other common operations.
Consent Management
checkConsent()
Checks if all required consent types have been granted by the customer.
function checkConsent(
requiredConsents: ConsentType[],
canTrack: any,
analytics: any
): boolean
Parameters:
requiredConsents - Array of consent types that must be granted
canTrack - Hydrogen’s canTrack function from analytics
analytics - Hydrogen’s analytics instance
Returns: true if all required consents are granted, false otherwise
Usage:
import { checkConsent, CONSENT_TYPES } from '@glood/hydrogen';
// Check if analytics consent is granted
const canSendAnalytics = checkConsent(
[CONSENT_TYPES.ANALYTICS],
canTrack,
analytics
);
// Check multiple consent types
const canSendMarketing = checkConsent(
[CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
canTrack,
analytics
);
if (canSendAnalytics) {
// Send analytics pixel
}
Implementation Details:
export function checkConsent(
requiredConsents: ConsentType[],
canTrack: any,
analytics: any
): boolean {
if (!requiredConsents || requiredConsents.length === 0) {
return true; // No consent required
}
return requiredConsents.every(consentType => {
switch (consentType) {
case 'analytics':
return analytics.customerPrivacy?.analyticsProcessingAllowed();
case 'marketing':
return analytics.customerPrivacy?.marketingAllowed();
case 'preferences':
return analytics.customerPrivacy?.preferencesProcessingAllowed();
case 'sale_of_data':
return analytics.customerPrivacy?.saleOfDataAllowed();
default:
return false;
}
});
}
Constants
DEFAULT_ENDPOINTS
Default API and pixel endpoints for all apps.
const DEFAULT_ENDPOINTS = {
recommendations: {
main: 'https://storefront.glood.ai',
pixel: 'https://events.glood.ai',
},
search: {
main: 'https://s-s.glood.ai',
pixel: 'https://s-pixel.glood.ai',
},
wishlist: {
main: 'https://w-s.glood.ai',
pixel: 'https://w-pixel.glood.ai',
},
} as const;
Usage:
import { DEFAULT_ENDPOINTS } from '@glood/hydrogen';
// Get recommendations endpoints
const recEndpoint = DEFAULT_ENDPOINTS.recommendations.main;
const recPixel = DEFAULT_ENDPOINTS.recommendations.pixel;
// Use in custom configuration
const customConfig = {
endpoint: DEFAULT_ENDPOINTS.search.main,
pixel: {
enabled: true,
endpoint: DEFAULT_ENDPOINTS.search.pixel,
consent: ['analytics'],
},
};
DEFAULT_PIXEL_CONFIG
Default pixel configuration settings.
const DEFAULT_PIXEL_CONFIG = {
enabled: true,
} as const;
ALL_EVENTS
Array of all supported event types.
const ALL_EVENTS = [
'page_viewed',
'product_viewed',
'collection_viewed',
'cart_viewed',
'search_viewed',
'search_submitted',
'custom_promotion_viewed',
'product_added_to_cart',
'product_removed_from_cart',
] as const;
Usage:
import { ALL_EVENTS } from '@glood/hydrogen';
// Check if event type is valid
function isValidEventType(eventType: string): boolean {
return ALL_EVENTS.includes(eventType as any);
}
// Get all event types
const eventTypes = [...ALL_EVENTS];
CONSENT_TYPES
Constants for all consent types.
const CONSENT_TYPES = {
ANALYTICS: 'analytics',
MARKETING: 'marketing',
PREFERENCES: 'preferences',
SALE_OF_DATA: 'sale_of_data',
} as const;
Usage:
import { CONSENT_TYPES } from '@glood/hydrogen';
// Use in configuration
const pixelConfig = {
enabled: true,
endpoint: 'https://events.glood.ai',
consent: [CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
};
// Type-safe consent checking
const requiredConsents = [
CONSENT_TYPES.ANALYTICS,
CONSENT_TYPES.PREFERENCES,
];
DEFAULT_PIXEL_CONSENT
Default consent requirements for each app.
const DEFAULT_PIXEL_CONSENT = {
recommendations: [CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
search: [CONSENT_TYPES.ANALYTICS],
wishlist: [CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.PREFERENCES],
} as const;
Usage:
import { DEFAULT_PIXEL_CONSENT } from '@glood/hydrogen';
// Get default consent for an app
const recConsent = DEFAULT_PIXEL_CONSENT.recommendations;
// ['analytics', 'marketing']
// Use in custom configuration
const customSearchConfig = {
endpoint: 'https://custom-search.glood.ai',
pixel: {
enabled: true,
endpoint: 'https://custom-pixel.glood.ai',
consent: DEFAULT_PIXEL_CONSENT.search, // ['analytics']
},
};
Transforms Shopify cart data to Glood pixel format.
function transformCartData(shopifyCart: any): any
Parameters:
shopifyCart - Shopify cart object from analytics events
Returns: Transformed cart data in Glood format, or null if cart is empty
Usage:
import { transformCartData } from '@glood/hydrogen';
// Transform cart from Shopify analytics event
const transformedCart = transformCartData(eventData.cart);
if (transformedCart) {
console.log('Cart total:', transformedCart.cost.totalAmount.amount);
console.log('Item count:', transformedCart.totalQuantity);
}
Transformation Example:
// Input: Shopify cart
{
id: 'gid://shopify/Cart/abc123?key=def456',
cost: {
totalAmount: { amount: '29.99', currencyCode: 'USD' }
},
lines: {
nodes: [{
cost: { totalAmount: { amount: '29.99', currencyCode: 'USD' } },
merchandise: {
id: 'gid://shopify/ProductVariant/123',
title: 'Blue T-Shirt',
price: { amount: '29.99', currencyCode: 'USD' },
product: {
id: 'gid://shopify/Product/456',
title: 'Cool T-Shirt',
handle: 'cool-t-shirt'
}
},
quantity: 1
}]
},
totalQuantity: 1
}
// Output: Glood format
{
id: 'abc123',
cost: {
totalAmount: { amount: 29.99, currencyCode: 'USD' }
},
lines: [{
cost: {
totalAmount: { amount: 29.99, currencyCode: 'USD' }
},
merchandise: {
id: '123',
title: 'Blue T-Shirt',
price: { amount: 29.99, currencyCode: 'USD' },
product: {
id: '456',
title: 'Cool T-Shirt',
url: '/products/cool-t-shirt',
// ... other fields
}
},
quantity: 1
}],
totalQuantity: 1
}
Transforms shop data to Glood pixel format.
function transformShopData(shopData: any, myShopifyDomain: string): any
Parameters:
shopData - Shop data from analytics events
myShopifyDomain - Your Shopify domain
Returns: Transformed shop data in Glood format
Usage:
import { transformShopData } from '@glood/hydrogen';
const transformedShop = transformShopData(
eventData.shop,
'my-store.myshopify.com'
);
console.log('Shop name:', transformedShop.name);
console.log('Currency:', transformedShop.paymentSettings.currencyCode);
createCustomerPrivacy()
Creates customer privacy object from analytics data.
function createCustomerPrivacy(analytics: any): any
Parameters:
analytics - Hydrogen analytics instance
Returns: Customer privacy object with consent status
Usage:
import { createCustomerPrivacy } from '@glood/hydrogen';
const customerPrivacy = createCustomerPrivacy(analytics);
console.log('Analytics allowed:', customerPrivacy.analyticsProcessingAllowed);
console.log('Marketing allowed:', customerPrivacy.marketingAllowed);
Output Example:
{
analyticsProcessingAllowed: true,
marketingAllowed: false,
preferencesProcessingAllowed: true,
saleOfDataAllowed: false,
}
getPageTitle()
Gets the current page title with fallback.
function getPageTitle(fallback: string = ''): string
Parameters:
fallback - Fallback title if document.title is not available
Returns: Current page title or fallback
Usage:
import { getPageTitle } from '@glood/hydrogen';
const title = getPageTitle('Default Title');
console.log('Page title:', title);
getCurrentUrl()
Gets the current URL from window or event data.
function getCurrentUrl(eventData?: any): string
Parameters:
eventData - Optional event data that might contain URL
Returns: Current URL string
Usage:
import { getCurrentUrl } from '@glood/hydrogen';
const url = getCurrentUrl(eventData);
console.log('Current URL:', url);
ID Generators
generateEventId()
Generates a unique event ID.
function generateEventId(): string
Returns: Unique event ID string
Usage:
import { generateEventId } from '@glood/hydrogen';
const eventId = generateEventId();
console.log('Event ID:', eventId); // "evt_abc123def456"
CookieStorage
Utility class for managing client IDs and session data.
getOrGenerateClientId()
Gets or generates a persistent client ID.
static getOrGenerateClientId(): string
Returns: Client ID string (persistent across browser sessions)
getOrGenerateSessionId()
Gets or generates a session ID.
static getOrGenerateSessionId(): string
Returns: Session ID string (valid for current browser session)
getOrGenerateRkUid()
Gets or generates a user ID for analytics.
static getOrGenerateRkUid(analytics: any): string
Parameters:
analytics - Hydrogen analytics instance
Returns: User ID string (prefers analytics customer ID, falls back to client ID)
Usage:
import { CookieStorage } from '@glood/hydrogen';
// Get persistent client ID
const clientId = CookieStorage.getOrGenerateClientId();
// Get session ID
const sessionId = CookieStorage.getOrGenerateSessionId();
// Get user ID for analytics
const userId = CookieStorage.getOrGenerateRkUid(analytics);
Extracts cart identifier from Shopify cart data.
function extractCartIdentifier(cart: any): string | null
Parameters:
cart - Shopify cart object
Returns: Cart identifier string or null if not available
Usage:
import { extractCartIdentifier } from '@glood/hydrogen';
const cartId = extractCartIdentifier(eventData.cart);
if (cartId) {
console.log('Cart identifier:', cartId);
}
Browser Context
browserContext
Utility object for getting browser environment information.
getContext()
Gets comprehensive browser context information.
getContext(): BrowserContext
Returns: Browser context object with page, user agent, screen, and locale information
Usage:
import { browserContext } from '@glood/hydrogen';
const context = browserContext.getContext();
console.log('Page URL:', context.page.url);
console.log('Screen size:', context.screen.width, 'x', context.screen.height);
console.log('Language:', context.language);
console.log('Timezone:', context.timezone);
Output Example:
{
page: {
url: 'https://store.myshopify.com/products/shirt',
title: 'Cool Shirt - My Store',
referrer: 'https://google.com'
},
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
screen: {
width: 1920,
height: 1080
},
language: 'en-US',
timezone: 'America/New_York'
}
Pixel Queue
getPixelQueue()
Gets the global pixel queue instance for sending events.
function getPixelQueue(debug?: boolean): PixelQueue
Parameters:
debug - Enable debug logging for pixel transmission
Returns: PixelQueue instance
Usage:
import { getPixelQueue } from '@glood/hydrogen';
const pixelQueue = getPixelQueue(true); // Enable debug mode
// Send a pixel event
pixelQueue.add({
endpoint: 'https://events.glood.ai',
data: {
event: {
id: 'evt_123',
name: 'product_viewed',
// ... event data
}
}
});
resetPixelQueue()
Resets the pixel queue (mainly for testing).
function resetPixelQueue(): void
Usage:
import { resetPixelQueue } from '@glood/hydrogen';
// Reset queue (typically used in tests)
resetPixelQueue();
Advanced Usage Examples
Custom Consent Checker
import { checkConsent, CONSENT_TYPES } from '@glood/hydrogen';
function createCustomConsentChecker(analytics: any) {
return {
canSendAnalytics: () => checkConsent([CONSENT_TYPES.ANALYTICS], null, analytics),
canSendMarketing: () => checkConsent([CONSENT_TYPES.MARKETING], null, analytics),
canPersonalize: () => checkConsent([CONSENT_TYPES.PREFERENCES], null, analytics),
canSellData: () => checkConsent([CONSENT_TYPES.SALE_OF_DATA], null, analytics),
// Custom combination checks
canSendRecommendations: () => checkConsent(
[CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
null,
analytics
),
canTrackWishlist: () => checkConsent(
[CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.PREFERENCES],
null,
analytics
),
};
}
// Usage
const consentChecker = createCustomConsentChecker(analytics);
if (consentChecker.canSendRecommendations()) {
// Send recommendations pixel
}
import {
transformCartData,
transformShopData,
generateEventId,
CookieStorage,
browserContext
} from '@glood/hydrogen';
function createCustomEventTransformer(client: GloodClient) {
return {
transformEvent(eventType: string, eventData: any) {
const baseEvent = {
id: generateEventId(),
name: eventType,
type: 'custom',
timestamp: new Date().toISOString(),
clientId: CookieStorage.getOrGenerateClientId(),
context: browserContext.getContext(),
};
const transformedData = {
customer: eventData.customer || null,
cart: eventData.cart ? transformCartData(eventData.cart) : null,
shop: transformShopData(eventData.shop, client.config.myShopifyDomain),
};
return {
event: baseEvent,
data: transformedData,
sessionId: CookieStorage.getOrGenerateSessionId(),
// Add custom fields
customMetadata: {
source: 'custom-transformer',
version: '1.0.0',
},
};
}
};
}
Environment-Specific Constants
import { DEFAULT_ENDPOINTS, CONSENT_TYPES } from '@glood/hydrogen';
function getEnvironmentConfig(env: string) {
const baseConfig = {
consent: {
minimal: [CONSENT_TYPES.ANALYTICS],
standard: [CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
full: [CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING, CONSENT_TYPES.PREFERENCES],
},
};
switch (env) {
case 'development':
return {
...baseConfig,
endpoints: {
recommendations: {
main: 'https://dev-storefront.glood.ai',
pixel: 'https://dev-events.glood.ai',
},
// ... other dev endpoints
},
pixelEnabled: false, // Disable pixels in dev
};
case 'staging':
return {
...baseConfig,
endpoints: {
recommendations: {
main: 'https://staging-storefront.glood.ai',
pixel: 'https://staging-events.glood.ai',
},
// ... other staging endpoints
},
pixelEnabled: true,
};
case 'production':
default:
return {
...baseConfig,
endpoints: DEFAULT_ENDPOINTS,
pixelEnabled: true,
};
}
}
Error Handling Utilities
import { transformCartData, transformShopData } from '@glood/hydrogen';
function safeTransform<T>(
transformer: (data: any) => T,
data: any,
fallback: T
): T {
try {
return transformer(data);
} catch (error) {
console.warn('Transform error:', error);
return fallback;
}
}
// Usage
const safeCart = safeTransform(transformCartData, eventData.cart, null);
const safeShop = safeTransform(
(shop) => transformShopData(shop, 'my-store.myshopify.com'),
eventData.shop,
{ name: 'Unknown Store' }
);
Consent Validation
import { checkConsent, CONSENT_TYPES } from '@glood/hydrogen';
function validateConsent(
requiredConsents: ConsentType[],
analytics: any
): { valid: boolean; missing: ConsentType[] } {
const missing: ConsentType[] = [];
for (const consentType of requiredConsents) {
if (!checkConsent([consentType], null, analytics)) {
missing.push(consentType);
}
}
return {
valid: missing.length === 0,
missing,
};
}
// Usage
const validation = validateConsent(
[CONSENT_TYPES.ANALYTICS, CONSENT_TYPES.MARKETING],
analytics
);
if (!validation.valid) {
console.log('Missing consents:', validation.missing);
}
Debounced Event Sending
import { getPixelQueue } from '@glood/hydrogen';
function createDebouncedPixelSender(delay: number = 100) {
let timeoutId: NodeJS.Timeout;
const queue: Array<{ endpoint: string; data: any }> = [];
return {
add(endpoint: string, data: any) {
queue.push({ endpoint, data });
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const pixelQueue = getPixelQueue();
queue.forEach(item => pixelQueue.add(item));
queue.length = 0; // Clear queue
}, delay);
}
};
}
Testing Utilities
Mock Analytics
function createMockAnalytics(consents: Partial<Record<ConsentType, boolean>> = {}) {
return {
customerPrivacy: {
analyticsProcessingAllowed: () => consents.analytics ?? true,
marketingAllowed: () => consents.marketing ?? false,
preferencesProcessingAllowed: () => consents.preferences ?? false,
saleOfDataAllowed: () => consents.sale_of_data ?? false,
},
subscribe: jest.fn(),
canTrack: jest.fn(() => true),
};
}
// Usage in tests
const mockAnalytics = createMockAnalytics({
analytics: true,
marketing: false,
});
const canSend = checkConsent([CONSENT_TYPES.ANALYTICS], null, mockAnalytics);
expect(canSend).toBe(true);
See Also