diff --git a/docs/INTEGRATION_LEGACY_RECOMMENDATIONS.md b/docs/INTEGRATION_LEGACY_RECOMMENDATIONS.md
index 51c9b8ec7..a546d171f 100644
--- a/docs/INTEGRATION_LEGACY_RECOMMENDATIONS.md
+++ b/docs/INTEGRATION_LEGACY_RECOMMENDATIONS.md
@@ -26,6 +26,7 @@ Context variables may be applied to individual recommendation profiles similar t
 | options.brands | array of brand strings | all | optional brand identifiers used in brand trending recommendation profiles |
 | options.branch | template branch overwrite | all | optional branch overwrite for recommendations template (advanced usage) |
 | options.filters | array of filters | all | optional recommendation filters |
+| options.query | string | all | query to search |
 | options.realtime | boolean | all | optional update recommendations if cart contents change (requires [cart attribute tracking](https://github.com/searchspring/snap/blob/main/docs/INTEGRATION_TRACKING.md)) |
 | options.blockedItems | array of strings | all | SKU values to identify which products to exclude from the response |
 | options.batched | boolean (default: `true`)| all | only applies to recommendation context, optional disable profile from being batched in a single request, can also be set globally [via config](https://github.com/searchspring/snap/tree/main/packages/snap-controller/src/Recommendation) | 
diff --git a/docs/INTEGRATION_RECOMMENDATIONS.md b/docs/INTEGRATION_RECOMMENDATIONS.md
index 5312157fa..b2ead6db2 100644
--- a/docs/INTEGRATION_RECOMMENDATIONS.md
+++ b/docs/INTEGRATION_RECOMMENDATIONS.md
@@ -33,6 +33,7 @@ Context variables are applied to individual recommendation profiles similar to h
 | Option | Value | Placement | Description | Required
 |---|---|:---:|---|:---:|
 | products | array of SKU strings | product detail page | SKU value(s) to identify the current product(s) being viewed | ✔️ |
+| blockedItems | array of strings | all | SKU values to identify which products to exclude from the response |   |
 | cart | array (or function that returns an array) of current cart skus | all | optional method of setting cart contents |   |
 | shopper.id | logged in user unique identifier | all | required for personalization functionallity if not provided to the bundle (global) context |   |
 
@@ -47,10 +48,9 @@ Context variables are applied to individual recommendation profiles similar to h
 | options.brands | array of brand strings | all | optional brand identifiers used in brand trending recommendation profiles |   |
 | options.branch | template branch overwrite | all | optional branch overwrite for recommendations template (advanced usage) |   |
 | options.dedupe | boolean (default: `true`) | all | dedupe products across all profiles in the batch |   |
-| options.searchTerm | string | all | query to search |   |
+| options.query | string | dynamic custom | query to search |   |
 | options.filters | array of filters | all | optional recommendation filters |   |
 | options.realtime | boolean | all | optional update recommendations if cart contents change (requires [cart attribute tracking](https://github.com/searchspring/snap/blob/main/docs/INTEGRATION_TRACKING.md)) |   |
-| options.blockedItems | array of strings | all | SKU values to identify which products to exclude from the response |   |
 | options.limit | number (default: 20, max: 20) | all | optional maximum number of results to display, can also be set globally [via config globals](https://github.com/searchspring/snap/tree/main/packages/snap-controller/src/Recommendation) |   |
 
 
diff --git a/packages/snap-client/src/Client/apis/Recommend.test.ts b/packages/snap-client/src/Client/apis/Recommend.test.ts
index 1d382253f..acbd9b476 100644
--- a/packages/snap-client/src/Client/apis/Recommend.test.ts
+++ b/packages/snap-client/src/Client/apis/Recommend.test.ts
@@ -3,7 +3,7 @@ import { ApiConfiguration } from './Abstract';
 import { RecommendAPI } from './Recommend';
 import { MockData } from '@searchspring/snap-shared';
 
-import type { PostRecommendAPISpec } from '../../types';
+import type { RecommendPostRequestModel } from '../../types';
 
 const mockData = new MockData();
 
@@ -63,7 +63,7 @@ describe('Recommend Api', () => {
 			},
 		};
 
-		const requestParameters: PostRecommendAPISpec = {
+		const requestParameters: RecommendPostRequestModel = {
 			siteId: '8uyt2m',
 			profiles: [
 				{
@@ -147,14 +147,14 @@ describe('Recommend Api', () => {
 
 		api.batchRecommendations({
 			tag: 'similar',
-			limits: 14,
+			limit: 14,
 			batched: true,
 			...batchParams,
 		});
 
 		api.batchRecommendations({
 			tag: 'crossSell',
-			limits: 10,
+			limit: 10,
 			batched: true,
 			...batchParams,
 		});
@@ -167,7 +167,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"similar","limit":14},{"tag":"crossSell","limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"similar","limit":14},{"tag":"crossSell","limit":10}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -185,14 +185,14 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'similar',
 			categories: ['shirts'],
-			limits: 14,
+			limit: 14,
 			batched: true,
 			...batchParams,
 		});
 		//no category
 		api.batchRecommendations({
 			tag: 'crossSell',
-			limits: 10,
+			limit: 10,
 			batched: true,
 			...batchParams,
 		});
@@ -200,7 +200,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'crossSell',
 			categories: ['pants'],
-			limits: 10,
+			limit: 10,
 			batched: true,
 			...batchParams,
 		});
@@ -213,7 +213,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"similar","categories":["shirts"],"limit":14},{"tag":"crossSell","limit":10},{"tag":"crossSell","categories":["pants"],"limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"similar","categories":["shirts"],"limit":14},{"tag":"crossSell","limit":10},{"tag":"crossSell","categories":["pants"],"limit":10}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -231,7 +231,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'similar',
 			brands: ['shirts'],
-			limits: 14,
+			limit: 14,
 			batched: true,
 			...batchParams,
 		});
@@ -239,7 +239,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'crossSell',
 			brands: ['pants', 'pants2'],
-			limits: 10,
+			limit: 10,
 			batched: true,
 			...batchParams,
 		});
@@ -252,7 +252,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"similar","brands":["shirts"],"limit":14},{"tag":"crossSell","brands":["pants","pants2"],"limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"similar","brands":["shirts"],"limit":14},{"tag":"crossSell","brands":["pants","pants2"],"limit":10}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -270,7 +270,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'similar',
 			categories: ['shirts'],
-			limits: 14,
+			limit: 14,
 			order: 3,
 			batched: true,
 			...batchParams,
@@ -278,14 +278,14 @@ describe('Recommend Api', () => {
 		//no order
 		api.batchRecommendations({
 			tag: 'crossSell',
-			limits: 10,
+			limit: 10,
 			batched: true,
 			...batchParams,
 		});
 		//no category
 		api.batchRecommendations({
 			tag: 'crossSell',
-			limits: 10,
+			limit: 10,
 			order: 2,
 			batched: true,
 			...batchParams,
@@ -294,7 +294,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'crossSell',
 			categories: ['pants'],
-			limits: 10,
+			limit: 10,
 			order: 1,
 			batched: true,
 			...batchParams,
@@ -305,7 +305,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"crossSell","categories":["pants"],"limit":10},{"tag":"crossSell","limit":10},{"tag":"similar","categories":["shirts"],"limit":14},{"tag":"crossSell","limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"crossSell","categories":["pants"],"limit":10},{"tag":"crossSell","limit":10},{"tag":"similar","categories":["shirts"],"limit":14},{"tag":"crossSell","limit":10}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		//add delay for paramBatch.timeout
@@ -326,7 +326,7 @@ describe('Recommend Api', () => {
 		const promise1 = api.batchRecommendations({
 			tag: 'similar',
 			categories: ['shirts'],
-			limits: 10,
+			limit: 10,
 			order: 2,
 			batched: true,
 			...batchParams,
@@ -335,7 +335,7 @@ describe('Recommend Api', () => {
 		const promise2 = api.batchRecommendations({
 			tag: 'crosssell',
 			categories: ['dress'],
-			limits: 20,
+			limit: 20,
 			order: 1,
 			batched: true,
 			...batchParams,
@@ -349,7 +349,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"crosssell","categories":["dress"],"limit":20},{"tag":"similar","categories":["shirts"],"limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"crosssell","categories":["dress"],"limit":20},{"tag":"similar","categories":["shirts"],"limit":10}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -371,7 +371,7 @@ describe('Recommend Api', () => {
 
 		api.batchRecommendations({
 			tag: 'crossSell',
-			limits: 10,
+			limit: 10,
 			filters: [
 				{
 					type: 'value',
@@ -389,7 +389,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"crossSell","limit":10}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"],"filters":[{"field":"color","type":"=","values":["red"]}]}',
+			body: '{"profiles":[{"tag":"crossSell","limit":10,"filters":[{"field":"color","type":"=","values":["red"]}]}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -407,7 +407,7 @@ describe('Recommend Api', () => {
 		api.batchRecommendations({
 			tag: 'crossSell',
 			...batchParams,
-			limits: undefined,
+			limit: undefined,
 		});
 
 		//add delay for paramBatch.timeout
@@ -417,7 +417,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"crossSell","limit":20}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"crossSell","limit":20}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -465,7 +465,7 @@ describe('Recommend Api', () => {
 			headers: {
 				'Content-Type': 'text/plain',
 			},
-			body: '{"profiles":[{"tag":"crossSell","limit":20}],"siteId":"8uyt2m","product":"marnie-runner-2-7x10","blockedItems":["blocked_sku1","blocked_sku2"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
+			body: '{"profiles":[{"tag":"crossSell","limit":20}],"siteId":"8uyt2m","products":["marnie-runner-2-7x10"],"blockedItems":["blocked_sku1","blocked_sku2"],"lastViewed":["marnie-runner-2-7x10","ruby-runner-2-7x10","abbie-runner-2-7x10","riley-4x6","joely-5x8","helena-4x6","kwame-4x6","sadie-4x6","candice-runner-2-7x10","esmeray-4x6","camilla-230x160","candice-4x6","sahara-4x6","dayna-4x6","moema-4x6"]}',
 		};
 
 		expect(requestMock).toHaveBeenCalledWith(RequestUrl, POSTParams);
@@ -487,10 +487,15 @@ describe('Recommend Api', () => {
 					return {
 						tag: index.toString(),
 						limit: 20,
+						filters: [
+							{ field: 'color', type: '=', values: ['blue'] },
+							{ field: 'price', type: '>=', values: [0] },
+							{ field: 'price', type: '<=', values: [20] },
+						],
 					};
 				}),
 				siteId: '8uyt2m',
-				product: 'marnie-runner-2-7x10',
+				products: ['marnie-runner-2-7x10'],
 				lastViewed: [
 					'marnie-runner-2-7x10',
 					'ruby-runner-2-7x10',
@@ -508,11 +513,6 @@ describe('Recommend Api', () => {
 					'dayna-4x6',
 					'moema-4x6',
 				],
-				filters: [
-					{ field: 'color', type: '=', values: ['blue'] },
-					{ field: 'price', type: '>=', values: [0] },
-					{ field: 'price', type: '<=', values: [20] },
-				],
 			}),
 		};
 
diff --git a/packages/snap-client/src/Client/apis/Recommend.ts b/packages/snap-client/src/Client/apis/Recommend.ts
index 32cea86c1..593d3c559 100644
--- a/packages/snap-client/src/Client/apis/Recommend.ts
+++ b/packages/snap-client/src/Client/apis/Recommend.ts
@@ -1,8 +1,8 @@
 import { API, ApiConfiguration } from './Abstract';
-import { HTTPHeaders, PostRecommendRequestFiltersModel } from '../../types';
+import { HTTPHeaders, RecommendPostRequestFiltersModel, RecommendPostRequestProfileModel } from '../../types';
 import { AppMode } from '@searchspring/snap-toolbox';
 import { transformRecommendationFiltersPost } from '../transforms';
-import { ProfileRequestModel, ProfileResponseModel, RecommendResponseModel, RecommendRequestModel, PostRecommendAPISpec } from '../../types';
+import { ProfileRequestModel, ProfileResponseModel, RecommendResponseModel, RecommendRequestModel, RecommendPostRequestModel } from '../../types';
 
 class Deferred {
 	promise: Promise<any>;
@@ -27,7 +27,7 @@ export class RecommendAPI extends API {
 	private batches: {
 		[key: string]: {
 			timeout: number | NodeJS.Timeout;
-			request: PostRecommendAPISpec;
+			request: RecommendPostRequestModel;
 			entries: BatchEntry[];
 		};
 	};
@@ -61,22 +61,8 @@ export class RecommendAPI extends API {
 		const batch = (this.batches[key] = this.batches[key] || { timeout: null, request: { profiles: [] }, entries: [] });
 		const deferred = new Deferred();
 
-		const { tag, limits, limit, query, filters, profileFilters, dedupe, categories, brands } = parameters;
-
-		const newParams = {
-			...parameters,
-			tag: tag,
-			categories,
-			brands,
-			limit: limit ? limit : limits ? (typeof limits == 'number' ? limits : limits[0]) : undefined,
-			searchTerm: query,
-			profileFilters,
-			dedupe,
-			filters,
-		};
-
 		// add each request to the list
-		batch.entries.push({ request: newParams, deferred: deferred });
+		batch.entries.push({ request: parameters, deferred: deferred });
 
 		// wait for all of the requests to come in
 		const timeoutClear = typeof window !== 'undefined' ? window.clearTimeout : clearTimeout;
@@ -92,29 +78,24 @@ export class RecommendAPI extends API {
 			// now that the requests are in proper order, map through them
 			// and build out the batches
 			batch.entries.map((entry) => {
-				const { tag, categories, brands, query, profileFilters, dedupe } = entry.request;
-				let limit = entry.request.limit;
+				const { tag, categories, brands, query, filters, dedupe } = entry.request;
 
-				if (!limit) {
-					limit = 20;
+				let transformedFilters;
+				if (filters) {
+					transformedFilters = transformRecommendationFiltersPost(filters) as RecommendPostRequestFiltersModel[];
 				}
 
-				const profile: any = {
+				const profile: RecommendPostRequestProfileModel = {
 					tag,
 					categories,
 					brands,
-					limit,
-					query,
-					filters: profileFilters,
+					limit: entry.request.limit || 20,
+					searchTerm: query,
+					filters: transformedFilters,
 					dedupe,
 				};
 
-				let transformedFilters;
-				if (profile.filters) {
-					transformedFilters = transformRecommendationFiltersPost(profile.filters) as PostRecommendRequestFiltersModel[];
-				}
-
-				batch.request.profiles?.push({ ...profile, filters: transformedFilters });
+				batch.request.profiles?.push(profile);
 
 				batch.request = {
 					...batch.request,
@@ -126,20 +107,18 @@ export class RecommendAPI extends API {
 					cart: parameters.cart,
 					lastViewed: parameters.lastViewed,
 					shopper: parameters.shopper,
-				} as PostRecommendAPISpec;
+				} as RecommendPostRequestModel;
 
-				// combine product data if both 'product' and 'products' are used
-				if (batch.request.product && Array.isArray(batch.request.products) && batch.request.products.indexOf(batch.request.product) == -1) {
-					batch.request.products = batch.request.products.concat(batch.request.product);
+				// use products request only and combine when needed
+				if (batch.request.product) {
+					if (Array.isArray(batch.request.products) && batch.request.products.indexOf(batch.request.product) == -1) {
+						batch.request.products = batch.request.products.concat(batch.request.product);
+					} else {
+						batch.request.products = [batch.request.product];
+					}
 
 					delete batch.request.product;
 				}
-
-				// transform global filters here
-				if (entry.request.filters) {
-					const globalFiltersToAdd = transformRecommendationFiltersPost(entry.request.filters!) as PostRecommendRequestFiltersModel[];
-					batch.request['filters'] = globalFiltersToAdd;
-				}
 			});
 
 			try {
@@ -151,7 +130,7 @@ export class RecommendAPI extends API {
 					batch.request['product'] = batch.request['product'].toString();
 				}
 
-				const response = await this.postRecommendations(batch.request as PostRecommendAPISpec);
+				const response = await this.postRecommendations(batch.request as RecommendPostRequestModel);
 
 				batch.entries?.forEach((entry, index) => {
 					entry.deferred.resolve([response[index]]);
@@ -166,7 +145,7 @@ export class RecommendAPI extends API {
 		return deferred.promise;
 	}
 
-	async postRecommendations(requestParameters: PostRecommendAPISpec): Promise<RecommendResponseModel> {
+	async postRecommendations(requestParameters: RecommendPostRequestModel): Promise<RecommendResponseModel> {
 		const headerParameters: HTTPHeaders = {};
 		headerParameters['Content-Type'] = 'text/plain';
 
diff --git a/packages/snap-client/src/Client/transforms/recommendationFiltersPost.ts b/packages/snap-client/src/Client/transforms/recommendationFiltersPost.ts
index 6b04e447f..3b164690a 100644
--- a/packages/snap-client/src/Client/transforms/recommendationFiltersPost.ts
+++ b/packages/snap-client/src/Client/transforms/recommendationFiltersPost.ts
@@ -1,7 +1,7 @@
-import { RecommendationRequestFilterModel, PostRecommendRequestFiltersModel } from '../../types';
+import { RecommendationRequestFilterModel, RecommendPostRequestFiltersModel } from '../../types';
 
 export const transformRecommendationFiltersPost = (filters: RecommendationRequestFilterModel[]) => {
-	const filterArray: PostRecommendRequestFiltersModel[] = [];
+	const filterArray: RecommendPostRequestFiltersModel[] = [];
 	filters.map((filter) => {
 		if (filter.type == 'value') {
 			//check if filterArray contains a filter for this value already
diff --git a/packages/snap-client/src/types.ts b/packages/snap-client/src/types.ts
index 4c3020068..5c1d50cae 100644
--- a/packages/snap-client/src/types.ts
+++ b/packages/snap-client/src/types.ts
@@ -104,7 +104,7 @@ export type TrendingResponseModel = {
 
 export type RecommendRequestModel = {
 	tag: string;
-	siteId: string;
+	siteId?: string;
 	product?: string;
 	products?: string[];
 	shopper?: string;
@@ -113,23 +113,21 @@ export type RecommendRequestModel = {
 	cart?: string[];
 	lastViewed?: string[];
 	test?: boolean;
+	branch?: string;
+	filters?: RecommendationRequestFilterModel[];
+	blockedItems?: string[];
 	batched?: boolean;
-	limits?: number | number[];
 	limit?: number;
 	order?: number;
-	filters?: RecommendationRequestFilterModel[];
-	blockedItems?: string[];
 	batchId?: number;
-	profileFilters?: RecommendationRequestFilterModel[];
 	query?: string;
 	dedupe?: boolean;
-	branch?: string;
 };
 
 //TODO: move to snapi
-export type PostRecommendAPISpec = {
+export type RecommendPostRequestModel = {
 	siteId: string;
-	profiles: (Omit<RecommendPostProfileObject, 'filters'> & { filters?: PostRecommendRequestFiltersModel[] })[];
+	profiles: RecommendPostRequestProfileModel[];
 	product?: string;
 	products?: string[];
 	shopper?: string;
@@ -138,10 +136,15 @@ export type PostRecommendAPISpec = {
 	test?: boolean;
 	withRecInfo?: boolean;
 	blockedItems?: string[];
-	filters?: PostRecommendRequestFiltersModel[];
+	filters?: RecommendPostRequestFiltersModel[];
+};
+
+export type RecommendPostRequestProfileModel = Omit<RecommendRequestProfileModel, 'filters' | 'query'> & {
+	filters?: RecommendPostRequestFiltersModel[];
+	searchTerm?: string;
 };
 
-export type RecommendPostProfileObject = {
+export type RecommendRequestProfileModel = {
 	tag: string;
 	categories?: string[];
 	brands?: string[];
@@ -151,7 +154,7 @@ export type RecommendPostProfileObject = {
 	filters?: RecommendationRequestFilterModel[];
 };
 
-export type PostRecommendRequestFiltersModel = {
+export type RecommendPostRequestFiltersModel = {
 	field: string;
 	type: '=' | '==' | '===' | '!=' | '!==' | '>' | '<' | '>=' | '<=';
 	values: (string | number)[];
diff --git a/packages/snap-preact-demo/src/components/Recommendations/Recs/Recs.tsx b/packages/snap-preact-demo/src/components/Recommendations/Recs/Recs.tsx
index 13b16fecd..460906692 100644
--- a/packages/snap-preact-demo/src/components/Recommendations/Recs/Recs.tsx
+++ b/packages/snap-preact-demo/src/components/Recommendations/Recs/Recs.tsx
@@ -1,7 +1,7 @@
 import { h, Component } from 'preact';
 import { observer } from 'mobx-react';
 
-import { Carousel, Recommendation, Result } from '@searchspring/snap-preact-components';
+import { Recommendation, Result } from '@searchspring/snap-preact-components';
 
 type RecsProps = {
 	controller?: RecommendationController;
@@ -22,18 +22,12 @@ export class Recs extends Component<RecsProps> {
 	render() {
 		const controller = this.props.controller;
 		const store = controller?.store;
-		const arr = Array.from(Array(9).keys());
+		const parameters = store?.profile?.display?.templateParameters;
 
 		return (
 			<div>
-				<Carousel>
-					{arr.map((num) => (
-						<div>{num}!!!</div>
-					))}
-				</Carousel>
-
 				<hr style={{ margin: '20px 0' }} />
-				<Recommendation controller={controller} title={'Recommended For You'} speed={0} lazyRender={{ enabled: false }}>
+				<Recommendation controller={controller} title={parameters.title} speed={0} lazyRender={{ enabled: false }}>
 					{store.results.map((result) => (
 						<Result controller={controller} result={result}></Result>
 					))}
diff --git a/packages/snap-preact-demo/tests/cypress/e2e/recommendation/recommendationBundle.cy.js b/packages/snap-preact-demo/tests/cypress/e2e/recommendation/recommendationBundle.cy.js
index 3820ff733..7d5e40a97 100644
--- a/packages/snap-preact-demo/tests/cypress/e2e/recommendation/recommendationBundle.cy.js
+++ b/packages/snap-preact-demo/tests/cypress/e2e/recommendation/recommendationBundle.cy.js
@@ -46,7 +46,7 @@ describe('BundledRecommendations', () => {
 	describe('Tests Bundle', () => {
 		it('has a controller', function () {
 			cy.snapController(config?.selectors?.recommendation.controller).then(({ store }) => {
-				expect(store.config.globals.product.length).to.greaterThan(0);
+				expect(store.config.globals.products.length).to.greaterThan(0);
 			});
 		});
 
diff --git a/packages/snap-preact/src/Instantiators/RecommendationInstantiator.test.tsx b/packages/snap-preact/src/Instantiators/RecommendationInstantiator.test.tsx
index baa7aac61..a4afa9d04 100644
--- a/packages/snap-preact/src/Instantiators/RecommendationInstantiator.test.tsx
+++ b/packages/snap-preact/src/Instantiators/RecommendationInstantiator.test.tsx
@@ -280,6 +280,7 @@ describe('RecommendationInstantiator', () => {
 		document.body.innerHTML = `<script type="searchspring/recommend" profile="${DEFAULT_PROFILE}">
 			shopper = { id: 'snapdev' };
 			product = 'sku1';
+			custom = { some: 'thing' };
 			options = {
 				branch: 'testing',
 				siteId: 'abc123',
@@ -292,9 +293,9 @@ describe('RecommendationInstantiator', () => {
 						value: 'blue'
 					},
 					{
-						  type: 'range',
-						  field: 'price',
-						  value: { low: 0, high: 20 }
+						type: 'range',
+						field: 'price',
+						value: { low: 0, high: 20 }
 					}
 				],
 				brands: ['nike', 'h&m'],
@@ -316,6 +317,7 @@ describe('RecommendationInstantiator', () => {
 					id: 'snapdev',
 				},
 				product: 'sku1',
+				custom: { some: 'thing' },
 				options: {
 					branch: 'testing',
 					categories: ['cats', 'dogs'],
@@ -358,7 +360,7 @@ describe('RecommendationInstantiator', () => {
 			batchId: 1,
 			brands: ['nike', 'h&m'],
 			limit: 5,
-			product: 'sku1',
+			products: ['sku1'],
 			shopper: 'snapdev',
 			siteId: 'abc123',
 			tag: 'trending',
@@ -370,15 +372,20 @@ describe('RecommendationInstantiator', () => {
 			{
 				profile: 'trending',
 				target: '#tout1',
+				custom: { some: 'thing1' },
 				options: {
+					siteId: '8uyt2m',
 					limit: 1,
 					categories: ['1234'],
 					brands: ['12345'],
 					filters: [
 						{
-							field: 'color',
-							type: 'value',
-							value: 'red',
+							field: 'price',
+							type: 'range',
+							value: {
+								low: 20,
+								high: 40,
+							},
 						},
 					],
 				},
@@ -386,6 +393,7 @@ describe('RecommendationInstantiator', () => {
 			{
 				profile: 'similar',
 				target: '#tout2',
+				custom: { some: 'thing2' },
 				options: {
 					limit: 2,
 					categories: ['5678'],
@@ -406,41 +414,50 @@ describe('RecommendationInstantiator', () => {
 			<div id="tout1"></div>
 			<div id="tout2"></div>
 			<script type="searchspring/recommendations">
+				custom = { some: 'thing' };
 				globals = {
-					product: "C-AD-W1-1869P",
-					shopperId: 'snapdev',
+					products: ["C-AD-W1-1869P"],
+					shopper: {
+						id: 'snapdev',
+					},
 					blockedItems: ['1234','5678'],
-                    cart: ['5678']
+					cart: ['5678']
 				};
 				
 				profiles = [
 					{
 						profile: 'trending',
 						target: '#tout1',
+						custom: { some: 'thing1' },
 						options: {
+							siteId: '8uyt2m',
 							limit: 1,
 							categories: ["1234"],
 							brands: ["12345"],
 							filters: [{
-								field: 'color',
-								type: 'value',
-								value: "red"
+								field: 'price',
+								type: 'range',
+								value: {
+									low: 20,
+									high: 40
+								}
 							}]
 						}
 					},
 					{
 						profile: 'similar',
 						target: '#tout2',
+						custom: { some: 'thing2' },
 						options: {
-                            limit: 2,
-                            categories: ["5678"],
-                            brands: ["65432"],
-                            filters: [{
-                                field: 'color',
-                                type: 'value',
-                                value: "blue"
-                            }]
-                        },
+							limit: 2,
+							categories: ["5678"],
+							brands: ["65432"],
+							filters: [{
+								field: 'color',
+								type: 'value',
+								value: "blue"
+							}]
+						},
 					},
 				];
 			</script>
@@ -455,13 +472,14 @@ describe('RecommendationInstantiator', () => {
 		Object.keys(recommendationInstantiator.controller).forEach((controllerId, index) => {
 			const controller = recommendationInstantiator.controller[controllerId];
 			expect(controller.context).toStrictEqual({
+				custom: { some: 'thing' },
 				globals: {
-					product: 'C-AD-W1-1869P',
-					shopperId: 'snapdev',
+					products: ['C-AD-W1-1869P'],
+					shopper: { id: 'snapdev' },
 					blockedItems: ['1234', '5678'],
 					cart: ['5678'],
 				},
-				...profileContextArray[index],
+				profile: profileContextArray[index],
 			});
 		});
 		const batchId = recommendationInstantiator.controller[Object.keys(recommendationInstantiator.controller)[0]].store.config.batchId;
@@ -475,13 +493,18 @@ describe('RecommendationInstantiator', () => {
 			cart: ['5678'],
 			categories: ['1234'],
 			limit: 1,
-			profileFilters: [
+			filters: [
 				{
-					field: 'color',
-					type: 'value',
-					value: 'red',
+					field: 'price',
+					type: 'range',
+					value: {
+						low: 20,
+						high: 40,
+					},
 				},
 			],
+			products: ['C-AD-W1-1869P'],
+			shopper: 'snapdev',
 			batchId,
 			siteId: '8uyt2m',
 			tag: 'trending',
@@ -495,15 +518,17 @@ describe('RecommendationInstantiator', () => {
 			cart: ['5678'],
 			categories: ['5678'],
 			limit: 2,
-			profileFilters: [
+			filters: [
 				{
 					field: 'color',
 					type: 'value',
 					value: 'blue',
 				},
 			],
+			products: ['C-AD-W1-1869P'],
+			shopper: 'snapdev',
 			batchId,
-			siteId: '8uyt2m',
+			siteId: undefined,
 			tag: 'similar',
 		});
 	});
diff --git a/packages/snap-preact/src/Instantiators/RecommendationInstantiator.tsx b/packages/snap-preact/src/Instantiators/RecommendationInstantiator.tsx
index b0eefc8fb..e6779a52b 100644
--- a/packages/snap-preact/src/Instantiators/RecommendationInstantiator.tsx
+++ b/packages/snap-preact/src/Instantiators/RecommendationInstantiator.tsx
@@ -51,20 +51,24 @@ type RecommendationProfileCounts = {
 };
 
 type ProfileSpecificProfile = {
+	custom?: any;
+	options: Pick<RecommendRequestModel, 'siteId' | 'categories' | 'brands' | 'branch' | 'filters' | 'limit' | 'query' | 'dedupe'> & {
+		realtime?: boolean;
+	};
 	profile: string;
 	target: string;
-	options: Partial<RecommendRequestModel>;
 };
 
 type ProfileSpecificGlobals = {
-	products?: string[];
-	siteId?: string;
+	blockedItems: string[];
 	cart?: string[] | (() => string[]);
+	products?: string[];
 	shopper?: { id?: string };
+	siteId?: string;
 };
 
-type ExtendedRecommendaitonTarget = Target & {
-	context?: ProfileSpecificProfile;
+type ExtendedRecommendaitonProfileTarget = Target & {
+	profile?: ProfileSpecificProfile;
 };
 
 export class RecommendationInstantiator {
@@ -146,92 +150,72 @@ export class RecommendationInstantiator {
 			],
 			async (target: Target, elem: Element | undefined, originalElem: Element | undefined) => {
 				const elemContext = getContext(
-					['shopperId', 'shopper', 'product', 'products', 'seed', 'cart', 'options', 'profile', 'profiles', 'globals', 'custom'],
+					['shopperId', 'shopper', 'product', 'products', 'seed', 'cart', 'options', 'profile', 'custom', 'profiles', 'globals'],
 					(originalElem || elem) as HTMLScriptElement
 				);
 
-				const context: ContextVariables = deepmerge(this.context, elemContext);
+				if (elemContext.profiles && elemContext.profiles.length) {
+					// using the new script integration structure
 
-				const profiles = context.profiles as ProfileSpecificProfile[];
-				const globals = context.globals as ProfileSpecificGlobals;
+					// type the new profile specific integration context variables
+					const scriptContextProfiles = elemContext.profiles as ProfileSpecificProfile[];
+					const scriptContextGlobals = elemContext.globals as ProfileSpecificGlobals;
 
-				// controller globals and shared things
+					// grab from globals
+					const requestGlobals: Partial<RecommendRequestModel> = {
+						blockedItems: scriptContextGlobals.blockedItems,
+						cart: scriptContextGlobals.cart && getArrayFunc(scriptContextGlobals.cart),
+						products: scriptContextGlobals.products,
+						shopper: scriptContextGlobals.shopper?.id,
+						siteId: scriptContextGlobals.siteId,
+						batchId: Math.random(),
+					};
 
-				if (profiles && profiles.length) {
-					const targetsArr: ExtendedRecommendaitonTarget[] = [];
-					const batchId = Math.random();
+					const targetsArr: ExtendedRecommendaitonProfileTarget[] = [];
 
-					profiles.forEach((profile) => {
+					// build out the targets array for each profile
+					scriptContextProfiles.forEach((profile) => {
 						if (profile.target) {
 							const targetObj = {
 								selector: profile.target,
 								autoRetarget: true,
 								clickRetarget: true,
-								context: profile,
+								profile,
 							};
 
 							targetsArr.push(targetObj);
 						}
 					});
 
-					new DomTargeter(targetsArr, async (target: ExtendedRecommendaitonTarget, elem: Element | undefined, originalElem: Element | undefined) => {
-						const profileContext: ContextVariables = deepmerge(this.context, { ...target.context, globals });
-
-						const { options: profileOptions } = profileContext;
-						const controllerGlobals: Partial<RecommendRequestModel> = {};
-
-						const tag = profileContext.profile;
-
-						// context globals
-						if (profileContext.globals) {
-							if (profileContext.globals.siteId) {
-								controllerGlobals.siteId = profileContext.globals.siteId;
-							}
-							if (profileContext.globals.products) {
-								controllerGlobals.products = profileContext.globals.products;
-							}
-							if (profileContext.globals.blockedItems) {
-								controllerGlobals.blockedItems = profileContext.globals.blockedItems;
-							}
-							if (profileContext.globals.cart) {
-								controllerGlobals.cart = profileContext.globals.cart;
+					new DomTargeter(
+						targetsArr,
+						async (target: ExtendedRecommendaitonProfileTarget, elem: Element | undefined, originalElem: Element | undefined) => {
+							if (target.profile?.profile) {
+								const profileRequestGlobals: RecommendRequestModel = { ...requestGlobals, ...target.profile?.options, tag: target.profile.profile };
+								const profileContext: ContextVariables = deepmerge(this.context, { globals: scriptContextGlobals, profile: target.profile });
+								if (elemContext.custom) {
+									profileContext.custom = elemContext.custom;
+								}
+
+								readyTheController(this, elem, profileContext, profileCount, originalElem, profileRequestGlobals);
 							}
 						}
-
-						if (profileOptions?.filters) {
-							controllerGlobals.profileFilters = profileOptions.filters;
-						}
-
-						if (typeof profileOptions?.dedupe == 'boolean') {
-							controllerGlobals.dedupe = profileOptions.dedupe;
-						}
-
-						readyTheController(this, elem, profileContext, profileCount, originalElem, batchId, controllerGlobals, tag);
-					});
+					);
 				} else {
-					const { product, seed, options } = context;
-
-					const controllerGlobals: any = {};
-
-					const tag = elem?.getAttribute('searchspring-recommend');
-
-					if (product || seed) {
-						controllerGlobals.product = product || seed;
-					}
-
-					if (options?.siteId) {
-						controllerGlobals.siteId = options.siteId;
-					}
-
-					if (options?.branch) {
-						controllerGlobals.branch = options.branch;
-					}
-
-					if (options?.filters) {
-						controllerGlobals.filters = options.filters;
-					}
-
-					readyTheController(this, elem, context, profileCount, originalElem, 1, controllerGlobals, tag);
+					// using the "legacy" method
+					const { profile, products, product, seed, options, batched, shopper, shopperId } = elemContext;
+
+					const profileRequestGlobals: Partial<RecommendRequestModel> = {
+						tag: profile,
+						batched: batched ?? true,
+						batchId: 1,
+						products: products || (product && [product]) || (seed && [seed]),
+						cart: elemContext.cart && getArrayFunc(elemContext.cart),
+						shopper: shopper?.id || shopperId,
+						...options,
+					};
+
+					readyTheController(this, elem, elemContext, profileCount, originalElem, profileRequestGlobals);
 				}
 			}
 		);
@@ -256,76 +240,38 @@ async function readyTheController(
 	context: ContextVariables,
 	profileCount: RecommendationProfileCounts,
 	elem: Element | undefined,
-	batchId: number,
-	controllerGlobals: Partial<RecommendationControllerConfig>,
-	tag: string | null | undefined
+	controllerGlobals: Partial<RecommendationControllerConfig>
 ) {
-	const { shopper, shopperId, products, cart, options } = context;
-	const blockedItems = context.options?.blockedItems;
+	const { batched, batchId, realtime, cart, tag } = controllerGlobals;
 
 	if (!tag) {
 		// FEEDBACK: change message depending on script integration type (profile vs. legacy)
-		instance.logger.warn(`'profile' attribute is missing from <script> tag, skipping this profile`, elem);
+		instance.logger.warn(`'profile' is missing from <script> tag, skipping this profile`, elem);
 		return;
 	}
 
-	if (shopper || shopperId) {
-		controllerGlobals.shopper = shopper?.id || shopperId;
-	}
-	if (products) {
-		controllerGlobals.products = products;
-	}
-	if (options?.query) {
-		controllerGlobals.query = options.query;
-	}
-
-	if (options?.categories) {
-		controllerGlobals.categories = options.categories;
-	}
-	if (options?.brands) {
-		controllerGlobals.brands = options.brands;
-	}
-	if (options?.limit && Number.isInteger(Number(options?.limit))) {
-		controllerGlobals.limit = Number(options?.limit);
-	}
-	if (blockedItems && Array.isArray(blockedItems)) {
-		controllerGlobals.blockedItems = blockedItems;
-	}
-
-	let cartContents;
-	if (typeof cart === 'function') {
-		try {
-			const cartFuncContents = cart();
-			if (Array.isArray(cartFuncContents)) {
-				cartContents = cartFuncContents;
-			}
-		} catch (e) {
-			instance.logger.warn(`Error getting cart contents from function`, e);
-		}
-	} else if (Array.isArray(cart)) {
-		cartContents = cart;
-	}
-	if (Array.isArray(cartContents)) {
-		instance.tracker.cookies.cart.set(cartContents);
-		controllerGlobals.cart = instance.tracker.cookies.cart.get();
+	if (Array.isArray(cart)) {
+		instance.tracker.cookies.cart.set(cart);
 	}
 
 	profileCount[tag] = profileCount[tag] + 1 || 1;
 
-	const defaultGlobals = {
+	const defaultGlobals: Partial<RecommendRequestModel> = {
 		limit: 20,
 	};
 
-	const globals = deepmerge(
-		deepmerge(deepmerge(defaultGlobals, instance.config.client?.globals || {}), (instance.config.config?.globals as any) || {}),
-		controllerGlobals
-	);
+	const globals: Partial<RecommendRequestModel> = deepmerge.all([
+		defaultGlobals,
+		instance.config.client?.globals || {},
+		instance.config.config?.globals || {},
+		controllerGlobals,
+	]);
 
 	const controllerConfig = {
 		id: `recommend_${tag}_${profileCount[tag] - 1}`,
 		tag,
-		batched: options?.batched ?? true,
-		realtime: Boolean(options?.realtime),
+		batched: batched ?? true,
+		realtime: Boolean(realtime),
 		batchId: batchId,
 		...instance.config.config,
 		globals,
@@ -365,11 +311,11 @@ async function readyTheController(
 			},
 			{ client: instance.client, tracker: instance.tracker }
 		);
-	}
 
-	instance.uses.forEach((attachements) => controller.use(attachements));
-	instance.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
-	instance.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
+		instance.uses.forEach((attachements) => controller.use(attachements));
+		instance.plugins.forEach((plugin) => controller.plugin(plugin.func, ...plugin.args));
+		instance.middleware.forEach((middleware) => controller.on(middleware.event, ...middleware.func));
+	}
 
 	// run a search on the controller if it has not yet and it is not currently
 	if (!controller.store.loaded && !controller.store.loading) {
@@ -425,3 +371,20 @@ async function readyTheController(
 		}
 	});
 }
+
+function getArrayFunc(arrayOrFunc: string[] | (() => string[])): string[] {
+	if (typeof arrayOrFunc === 'function') {
+		try {
+			const funcContents = arrayOrFunc();
+			if (Array.isArray(funcContents)) {
+				return funcContents;
+			}
+		} catch (e) {
+			// function didn't return an array
+		}
+	} else if (Array.isArray(arrayOrFunc)) {
+		return arrayOrFunc;
+	}
+
+	return [];
+}