Kigo Context - UI/UX Page Configuration
Kigo UI/UX Page Configuration System
Overview
The Kigo Page Configuration System enables SDK-hosted sites and white-label implementations using the Kigo TOP SDK to customize the components and content displayed on the homepage. This system supports injecting components into the existing layout or fully overriding it, without modifying core SDK functionality.
The configuration is defined under the uiuxOverride['page-configurations'] key within the SDK context and allows partners to tailor the homepage experience based on whether the user's location is available.
Priority & Structure
Each homepage variant (homepage-with-location and homepage-no-location) is resolved independently.
Configuration Priority
- SDK context override via
uiuxOverride['page-configurations']—fully_overridereplaces the configured layout;inject_at_indexmerges into it - Program-level configuration (set by Kigo; program, then partner, then the Kigo base experience)
Leave a page key unset or set it to null (the SDK default) to use the program-level configuration as-is.
Page Configuration Structure
type PageOverrideMode = "fully_override" | "inject_at_index";
type PageConfigurationsContext = {
"homepage-with-location": PageConfigurationContext;
"homepage-no-location": PageConfigurationContext;
};
type PageConfigurationContext = {
mode: PageOverrideMode;
components: PageComponentOverride[];
} | null;
type PageComponentOverride = {
page_component_configuration_id?: string; // Optional; generated when omitted
title: string;
show_title?: boolean; // Defaults to true
component_code_type: PageComponentType;
sorting_order: number; // Starts at 1
generic_offer_carousel_metadata?: GenericOfferCarouselMetadata; // generic_offer_carousel, local_offers_with_integrated_map
generic_category_grid?: GenericCategoryGridMetadata; // generic_category_grid
};
type PageComponentType =
| "generic_offer_carousel"
| "generic_category_grid"
| "local_offers_with_integrated_map"
| "component_share_location"
| "component_user_survey"
| "component_offer_map_no_location"
| "component_hero_advertisement_carousel"
| "component_premium_hero"
| "component_standard_hero"
| "component_dedicated_shelf"
| "component_trending_merchants"
| "component_sponsored_trending_merchants"
| "component_just_for_you"
| "popular_city_offers";Components with an unrecognized component_code_type render nothing.
Common Properties
| Property | Type | Description |
|---|---|---|
title | string | Section title displayed above the component |
show_title | boolean | Set to false to hide the section title. Supported by the premium hero, standard hero, dedicated shelf, and sponsored trending merchants components. Defaults to true |
component_code_type | PageComponentType | Which component to render (see Component Types) |
sorting_order | number | Position of the component (see below) |
page_component_configuration_id | string | Optional identifier for the section. A unique ID is generated when omitted |
Sorting Order
The sorting_order property determines the position of each component within its page configuration (homepage-with-location or homepage-no-location).
Key Points:
- Starts at 1: The first position is
sorting_order: 1 - Ascending order: Components are displayed in ascending order (1, 2, 3, etc.)
- Page-specific: Sorting is independent for each page type—
homepage-with-locationandhomepage-no-locationhave their own sequences - Unique values: Use a unique
sorting_orderfor each component - Mode-dependent: In
fully_overridemode only the relative order matters, so gaps (1, 3, 5) are fine. Ininject_at_indexmode,sorting_orderis the exact slot the component claims (see below)
Example:
components: [
{ title: 'Featured Deals', sorting_order: 1 }, // Displays first
{ title: 'Near Me', sorting_order: 2 }, // Displays second
{ title: 'Categories', sorting_order: 3 }, // Displays third
]Configuration Modes
1. Fully Override Mode
Mode: 'fully_override'
Completely replaces the program-level components with the components defined in the SDK context, sorted by sorting_order. This mode gives you full control over the page layout.
Use Cases:
- Complete UI redesign for specific partners
- Removing all default components
- Creating a fully custom homepage experience
Example:
'homepage-with-location': {
mode: 'fully_override',
components: [
// These components will replace ALL program-level components
]
}2. Inject at Index Mode
Mode: 'inject_at_index'
Injects custom components at specific positions within the program-level layout:
- Each context component claims the 1-based position given by its
sorting_order - Program-level components fill the remaining positions in their original order
- Hero components (
component_hero_advertisement_carousel,component_premium_hero,component_standard_hero) appear only once: injecting one removes the program-level component of the same type - Other component types (e.g.
generic_offer_carousel) can appear multiple times
Example: with program-level components [a1, a2, a3, a4, a5] and context components c2 (sorting_order: 2) and c4 (sorting_order: 4), the page renders a1, c2, a2, c4, a3, a4, a5.
Use Cases:
- Adding promotional content to existing layouts
- Inserting partner-specific components without losing default content
- Testing new components alongside existing ones
Example:
'homepage-with-location': {
mode: 'inject_at_index',
components: [
// These components will be injected at the position given by sorting_order
]
}Page Types
1. Homepage with Location
Key: 'homepage-with-location'
Used when the user has shared their location or the SDK context includes location data. This configuration enables location-based features such as nearby offers, distance calculations, and geo-filtered content.
Location-Specific Features:
dynamic_query_filterswithlatitude,longitude, andradiusare populated from the user's locationsearch_radius_unitcan be set to'MI'or'KM'instatic_query_filters- Proximity-based sorting and filtering
Example Configuration:
'homepage-with-location': {
mode: 'fully_override',
components: [
{
title: 'Lightning Deals',
component_code_type: 'generic_offer_carousel',
sorting_order: 1, // First component
generic_offer_carousel_metadata: {
subtitle: null,
minimum_required_offers_to_show: 1,
show_integrated_offer_map: false,
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: ['<catalog-filter-id>'],
single_offer_per_merchant: true,
return_count_only: false,
},
search_radius_unit: 'MI',
limit: 6,
},
dynamic_query_filters: {
latitude: null, // Populated from user location
longitude: null, // Populated from user location
radius: null, // Populated from user location
},
online_fallback: false,
},
go_to_link_above: 'true',
go_to_link_display_text: 'See all',
go_to_link_url_parameters: '?catalog_filter_ids=<catalog-filter-id>',
},
},
],
}2. Homepage without Location
Key: 'homepage-no-location'
Used when the user has not shared their location. This configuration displays content that doesn't require geographic data.
No-Location Characteristics:
- No
latitude,longitude, orradiusfilters - No
search_radius_unitrequired dynamic_query_filterstypically empty- Focus on online offers or national campaigns
- Selecting a "See all" link prompts the user to share their location before navigating
Example Configuration:
'homepage-no-location': {
mode: 'fully_override',
components: [
{
title: 'Online Deals',
component_code_type: 'generic_offer_carousel',
sorting_order: 1, // First component
generic_offer_carousel_metadata: {
subtitle: null,
minimum_required_offers_to_show: 3,
show_integrated_offer_map: false,
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: ['<catalog-filter-id>'],
redemption_types: ['online'],
single_offer_per_merchant: true,
return_count_only: false,
},
limit: 6,
// No search_radius_unit for no-location page
},
dynamic_query_filters: {}, // Empty - no location values
online_fallback: false,
},
go_to_link_above: 'true',
go_to_link_display_text: 'See all',
go_to_link_url_parameters: '?catalog_filter_ids=<catalog-filter-id>&redemption_types=online',
},
},
],
}Component Types
The following component types are available for page configurations:
| Type | Description | Metadata |
|---|---|---|
generic_offer_carousel | Horizontal carousel of offers from a query | generic_offer_carousel_metadata (required) |
generic_category_grid | Grid of category tiles for navigation | generic_category_grid (required) |
local_offers_with_integrated_map | Nearby offers with an integrated map | generic_offer_carousel_metadata (optional) |
component_share_location | Prompts users to share their location | — |
component_user_survey | User survey | — |
component_offer_map_no_location | Offer map that doesn't require user location | — |
component_hero_advertisement_carousel | Promotional banners in a carousel (legacy hero) | — |
component_premium_hero | Premium hero placement | — |
component_standard_hero | Standard hero placement | — |
component_dedicated_shelf | Dedicated shelf placement | — |
component_trending_merchants | Popular or trending merchants | — |
component_sponsored_trending_merchants | Sponsored trending merchants | — |
component_just_for_you | Personalized recommendations | — |
popular_city_offers | Popular local offers across cities | — |
Metadata other than generic_offer_carousel_metadata and generic_category_grid is ignored.
Generic Offer Carousel
Type: 'generic_offer_carousel'
Displays a horizontal scrollable carousel of offers based on query filters.
Metadata scopeThe
generic_offer_carousel_metadataobject applies togeneric_offer_carouselandlocal_offers_with_integrated_map. Other component types ignore it.
Metadata Structure:
generic_offer_carousel_metadata: {
subtitle?: string | null;
minimum_required_offers_to_show?: number | null;
show_integrated_offer_map: boolean;
saved_offer_query: SavedOfferQuery; // See "Saved Offer Query" section below
go_to_link_above?: 'true' | 'false' | null;
go_to_link_display_text?: string | null;
go_to_link_url_parameters?: string | null;
}Metadata Properties:
| Property | Type | Description |
|---|---|---|
subtitle | string | null | Optional subtitle displayed below the carousel title |
minimum_required_offers_to_show | number | null | Minimum number of offers required to display the carousel. Defaults to 3 when omitted |
show_integrated_offer_map | boolean | Required by the schema. Not currently used by the carousel; set to false |
saved_offer_query | object | Query configuration for fetching offers (see below) |
go_to_link_above | 'true' | 'false' | null | Position of the "go to" link: 'true' shows it above the carousel, 'false' below. Omit or null for no link |
go_to_link_display_text | string | null | Text for the "go to" link (e.g. "See all"). Required for the link to appear; there is no default text |
go_to_link_url_parameters | string | null | Query string for the offers page the link opens (e.g. "?catalog_filter_ids=<id>&redemption_types=online"). When omitted, the link uses the carousel's own query filters |
Local Offers with Integrated Map
Type: 'local_offers_with_integrated_map'
Displays nearby offers with a map. Accepts an optional generic_offer_carousel_metadata, of which saved_offer_query and minimum_required_offers_to_show (default 3) are used. saved_offer_query.online_fallback defaults to true for this component: set it to false to disable falling back to online offers when no local offers are found.
Generic Category Grid
Type: 'generic_category_grid'
Displays a grid of category tiles for navigation.
Metadata Structure:
generic_category_grid: {
generic_category_grid_configurations_id?: string; // Generated when omitted
subtitle?: string | null;
go_to_link_above?: 'true' | 'false' | null;
go_to_link_display_text?: string | null;
go_to_link_url_parameters?: string | null;
grid_item_metadata: Array<{
generic_category_grid_item_metadata_id?: string; // Generated when omitted
category?: string | null;
category_display_text?: string | null;
category_image_url?: string | null;
category_mui_icon_name?: string | null; // e.g. 'LunchDiningIcon'
go_to_link_parameters?: string | null; // e.g. '?redemption_types=online'
sort_order: number;
}>;
}Saved Offer Query
The saved_offer_query object defines the query parameters used to fetch offers from the Kigo Offers API. It maps to the GET /api/v1/offers endpoint parameters.
Structure:
saved_offer_query: {
static_query_filters: {
filter?: {
catalog_filter_ids?: string[]; // Curated offer collections
single_offer_per_merchant?: boolean;
return_count_only?: boolean;
offer_types?: string[];
redemption_types?: string[];
// ...other GET /offers filter params
};
search_radius_unit?: 'MI' | 'KM';
radius?: number;
limit?: number; // Defaults to 99
offset?: number; // Defaults to 0
sort_by?: Array<{ field: string; direction: string }>;
};
dynamic_query_filters: {
latitude?: number | null;
longitude?: number | null;
radius?: number | null;
};
online_fallback?: boolean;
}Static Query Filters
These are fixed parameters that don't change based on user context.
Filter parameters (inside filter):
| Property | Type | Description |
|---|---|---|
catalog_filter_ids | string[] | Catalog filter IDs for curated offer collections |
single_offer_per_merchant | boolean | If true, only shows one offer per merchant to avoid duplicates |
return_count_only | boolean | If true, only returns the count (set to false for carousel display) |
offer_types | string[] | e.g. bogo, free_with_purchase, percentage_savings, dollars_off, price_point, cash_back, merchandise, digital_gift_card, physical_gift_card, spend_and_get |
redemption_types | string[] | e.g. in_store, print, online, purchase, spend_and_get |
Other supported filter keys: categories, category_ids, commodities, commodity_groups, commodity_ids, country_code, eligibilities, exclude_offer_ids, is_available, lightning_deal, max_merchants, merchant_ids, merchant_source, search, tag_ids, tags.
Top-level parameters (beside filter):
| Property | Type | Description |
|---|---|---|
search_radius_unit | 'MI' | 'KM' | Unit for radius-based searches (Miles or Kilometers) |
radius | number | Search radius |
limit | number | Maximum number of offers to fetch (default 99) |
offset | number | Pagination offset (default 0) |
sort_by | Array<{ field, direction }> | Sort order, e.g. [{ field: 'distance', direction: 'ascending' }] |
Keys not listed above are ignored. Location parameters (latitude, longitude, radius, search_radius_unit) are only sent when dynamic_query_filters contains latitude or longitude.
Dynamic Query Filters
These filters are populated at runtime from the user's location. Set them to null to have the SDK fill them in:
| Property | Type | Description |
|---|---|---|
latitude | number | null | User's latitude (auto-populated from location) |
longitude | number | null | User's longitude (auto-populated from location) |
radius | number | null | Search radius (auto-populated from the user's search radius, default 50) |
A non-null value is used as-is instead of the user's value.
Online Fallback
| Property | Type | Description |
|---|---|---|
online_fallback | boolean | Used by local_offers_with_integrated_map only. If true (the default for that component), falls back to online offers when no local offers are found |
Catalog Filter IDs
The catalog_filter_ids array allows you to display curated collections of offers in your carousel. These IDs represent pre-configured offer sets that can be tailored for specific use cases.
What are Catalog Filter IDs?
Catalog filter IDs are unique identifiers for curated offer collections. They allow you to:
- Display specific categories of offers (e.g., Pizza, Dining, Shopping)
- Promote seasonal or featured deals
- Create themed offer sections
- Target specific merchant types
How to Get Catalog Filter IDs:
Contact the Kigo teamContact the Kigo team if you need custom catalog filter IDs for your implementation. We can create curated offer collections for specific sections like:
- "Pizza Deals" - Only pizza-related offers
- "Weekend Specials" - Curated weekend promotions
- "New Merchants" - Recently added merchant offers
- Custom collections based on your requirements
Example Usage:
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: [
'<pizza-deals-catalog-filter-id>',
'<featured-merchants-catalog-filter-id>',
],
single_offer_per_merchant: true,
return_count_only: false,
},
search_radius_unit: 'MI',
},
dynamic_query_filters: {
latitude: null,
longitude: null,
radius: null,
},
}Empty Catalog Filter IDs:
If you leave catalog_filter_ids as an empty array [] (or omit it), the carousel will display all available offers based on the other filter criteria (location, etc.):
filter: {
catalog_filter_ids: [], // Shows all offers (no specific collection filter)
}Complete Integration Example
This example shows a complete configuration with multiple carousels sorted by sorting_order:
window.Kigo.setContext({
uiuxOverride: {
"welcome-modal": { enabled: true },
"estimated-savings-count": { enabled: false },
"wallet-icon": { enabled: true },
"wallet-icon-url": {
url: "https://cdn.example.com/icons/wallet.svg",
},
"page-configurations": {
"homepage-with-location": {
mode: "fully_override",
components: [
{
title: "Lightning Deals",
component_code_type: "generic_offer_carousel",
sorting_order: 1, // Displays first
generic_offer_carousel_metadata: {
subtitle: null,
minimum_required_offers_to_show: 1,
show_integrated_offer_map: false,
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: ["<catalog-filter-id>"], // Contact Kigo for custom IDs
single_offer_per_merchant: true,
return_count_only: false,
},
search_radius_unit: "MI",
limit: 6,
},
dynamic_query_filters: {
latitude: null, // Auto-populated from user location
longitude: null, // Auto-populated from user location
radius: null, // Auto-populated from user location
},
},
go_to_link_above: "true",
go_to_link_display_text: "See all",
go_to_link_url_parameters: "?catalog_filter_ids=<catalog-filter-id>",
},
},
{
title: "Near Me",
component_code_type: "generic_offer_carousel",
sorting_order: 2, // Displays second
generic_offer_carousel_metadata: {
subtitle: "Offers in your area",
minimum_required_offers_to_show: 1,
show_integrated_offer_map: false,
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: [], // Empty = all offers
single_offer_per_merchant: true,
return_count_only: false,
},
search_radius_unit: "MI",
limit: 6,
sort_by: [{ field: "distance", direction: "ascending" }],
},
dynamic_query_filters: {
latitude: null,
longitude: null,
radius: null,
},
},
go_to_link_above: "true",
go_to_link_display_text: "See all",
// No go_to_link_url_parameters: the link uses this carousel's query
},
},
],
},
"homepage-no-location": {
mode: "fully_override",
components: [
{
title: "Share your location",
component_code_type: "component_share_location",
sorting_order: 1,
},
{
title: "Online Deals",
component_code_type: "generic_offer_carousel",
sorting_order: 2,
generic_offer_carousel_metadata: {
subtitle: null,
minimum_required_offers_to_show: 3,
show_integrated_offer_map: false,
saved_offer_query: {
static_query_filters: {
filter: {
catalog_filter_ids: ["<catalog-filter-id>"],
redemption_types: ["online"],
single_offer_per_merchant: true,
return_count_only: false,
},
limit: 6,
// No search_radius_unit for no-location page
},
dynamic_query_filters: {}, // Empty for no-location
},
go_to_link_above: "true",
go_to_link_display_text: "See all",
go_to_link_url_parameters: "?catalog_filter_ids=<catalog-filter-id>&redemption_types=online",
},
},
],
},
},
},
});
Catalog filter IDsFor custom
catalog_filter_ids(e.g., "Pizza Deals", "Featured Merchants"), contact the Kigo team. We can create curated offer collections tailored to your needs.
Best Practices
1. Choose the Right Mode
- Use
fully_overridewhen you need complete control over the page layout - Use
inject_at_indexwhen you want to preserve existing components and add new ones
2. Sorting Order Management
- Start with
sorting_order: 1for the first component - Use unique, sequential numbering (1, 2, 3...) for clear ordering
- In
fully_overridemode, you can leave gaps (1, 3, 5) to allow for future insertions without renumbering - In
inject_at_indexmode,sorting_orderis the exact position the component takes on the page - Remember: sorting is independent for each page type—components in
homepage-with-locationare sorted separately fromhomepage-no-location
3. Location Awareness
- Provide both
homepage-with-locationandhomepage-no-locationconfigurations when overriding the layout (an unset page uses the program-level layout) - Ensure location-based queries are only used in the
homepage-with-locationconfiguration - Include
latitude/longitudekeys indynamic_query_filtersfor any query that should use the user's location
4. Component Metadata
generic_offer_carousel_metadataapplies togeneric_offer_carouselandlocal_offers_with_integrated_map;generic_category_gridapplies togeneric_category_grid- Set
minimum_required_offers_to_showto control visibility thresholds - Use
single_offer_per_merchant: true(insidefilter) to avoid merchant duplication - Set appropriate
search_radius_unitfor your target audience ('MI'for US,'KM'for international)
5. Query Optimization
- The
saved_offer_querymaps to the GET /offers API; filter parameters go insidefilter - Use
catalog_filter_idsto target specific offer collections (contact Kigo team for custom IDs) - Set
return_count_only: falseto retrieve full offer details for display - Set a
limitto control how many offers each carousel fetches (default99) - Use empty
catalog_filter_ids: []to show all offers without collection filtering
6. Navigation Links
- Set both
go_to_link_aboveandgo_to_link_display_textto show a "See all" link - Keep
go_to_link_display_textconcise and actionable - Use
go_to_link_url_parametersas an offers-page query string (e.g.?catalog_filter_ids=<id>), or omit it to reuse the carousel's own filters
Troubleshooting
Common Issues
-
Components not appearing:
- Verify
modeis set correctly (fully_overrideorinject_at_index) - Check that
component_code_typeis one of the supported types - Ensure component metadata structure matches expected schema (
generic_offer_carouselrequiresgeneric_offer_carousel_metadata;generic_category_gridrequiresgeneric_category_grid)
- Verify
-
Location-based queries not working:
- Confirm user has shared location or SDK context includes location data
- Verify
dynamic_query_filtersincludeslatitudeandlongitudekeys - Verify
search_radius_unitis set instatic_query_filters
-
Offers not showing in carousel:
- Verify
catalog_filter_idsare valid - Check the
minimum_required_offers_to_showthreshold (default3) - Ensure filter parameters such as
single_offer_per_merchantandreturn_count_onlyare insidefilter - Ensure
return_count_onlyis set tofalse
- Verify
-
"See all" link not showing:
- Set
go_to_link_aboveto'true'or'false'and providego_to_link_display_text
- Set
-
Override not taking effect:
- Verify configuration is in the correct format
- Check browser console for validation errors
-
Wrong page configuration loading:
- Confirm location detection is working properly
- Verify both configurations are defined
Summary
The page configuration system provides partners and hosted sites with powerful tools to customize homepage layouts and content. By supporting both location-aware and location-free configurations, partners can deliver optimized experiences regardless of user location sharing preferences. The dual-mode system (fully_override vs inject_at_index) enables everything from complete redesigns to subtle enhancements—all without modifying core SDK logic.
This flexibility allows partners to align the user experience with their brand guidelines, business objectives, and user engagement strategies while maintaining consistency with the Kigo platform's core functionality.
Updated 6 days ago