Skip to content

MarketerAI — Creating Rules with Analytics Filters ​

Table of Contents ​

  1. Overview
  2. Current Rule Creation Flow
  3. Analytics Filter Data Structure
  4. Available Analytics Columns
  5. How the Filter Is Displayed in the UI
  6. Expected System Behavior
  7. Known Issues and Required Fixes

Overview ​

Marketer AI allows users to create product rules based on analytics data from advertising platforms — including Google Ads, Google Analytics 4, and Microsoft Ads. For example, a user can say:

"For products where Google Ads conversions were greater than 5 in the last 30 days, set custom label 0 to 'Marketer'"

The system should translate this command into a complete rule with a correctly configured analytics filter — including the time range.


Current Rule Creation Flow ​

End-to-end path ​

User (chat)
    ↓
Marketer AI (LLM + MCP tools — repo: sembot_public-mcp)
    ↓  calls tool create_product_rule
POST /api/public/v1/projects/{project}/product-rules
    ↓  App\Http\Controllers\Api\PublicApi\Rules\ProductRulesController
    ↓  validation: App\Http\Requests\Api\Google\Merchant\Rules\StoreRuleRequest
    ↓              → App\Http\Requests\Api\FilteredRequest (filter validation)
    ↓  saved to DB: Rule (column `filters` — JSON)
    ↓  dispatch: BulkMassAction (queue products_mass_actions)
        ↓  when rule executes:
        App\Services\Products\AdditionalDataSource\AdditionalDataSourceService::processFilters()
            ↓  fetches data from the external platform for analytics filters
            ↓  replaces the analytics filter with a filter by product IDs

Components involved in analytics filter processing ​

ComponentFileResponsibility
AdditionalDataSourceServiceapp/Services/Products/AdditionalDataSource/AdditionalDataSourceService.phpIdentifies analytics filters, calls external APIs
GoogleAdsProductsDataSourceapp/Services/Products/AdditionalDataSource/GoogleAdsProductsDataSource.phpFetches data from the Google Ads API for the filtered date range
GoogleAnalytics4ProductsDataSourceapp/Services/Products/AdditionalDataSource/GoogleAnalytics4ProductsDataSource.phpFetches data from the GA4 API
MicrosoftAdvertisingProductsDataSourceapp/Services/Products/AdditionalDataSource/MicrosoftAdvertisingProductsDataSource.phpFetches data from the Microsoft Ads API
FilteredRequestapp/Http/Requests/Api/FilteredRequest.phpValidates filter structure — requires project_connection_id for analytics filters

How an analytics filter is processed when a rule executes ​

When processing BulkMassAction, AdditionalDataSourceService::processFilters() does the following for each analytics filter:

  1. Identifies that param comes from an external source (e.g. google_ads_conversions)
  2. Creates a connector (GoogleAdsProductsDataSource) with the project_connection_id connection
  3. Uses sub_days or start_date/end_date to determine the time window for the platform query
  4. Retrieves a list of product identifiers that meet the condition from the platform
  5. Replaces the analytics filter with a filter param: google_product_id, symbol: in, value: [id1, id2, ...]
  6. Further rule processing operates only on the local product database

Analytics Filter Data Structure ​

JSON stored in the database (filters column of the rules table) ​

json
{
  "filterGroups": [
    {
      "filters": [
        {
          "param": "google_ads_conversions",
          "symbol": ">",
          "value": 5,
          "project_connection_id": 123,
          "sub_days": 30,
          "translate_key": "connection_period"
        }
      ]
    }
  ]
}

Analytics filter field descriptions ​

FieldTypeRequiredDescription
paramstringyesAnalytics metric name (see section below)
symbolstringyesComparison operator: >, <, =, !=, >=, <=, is_empty, not_empty
valuenumber/stringyesThreshold value for comparison
project_connection_idintegeryesID of the project's connection to the platform (e.g. a specific Google Ads account)
sub_daysintegerconditional*Number of days back for a relative date (e.g. 30 = last 30 days)
start_datestring (YYYY-MM-DD)conditional*Start date for a fixed date range
end_datestring (YYYY-MM-DD)conditional*End date for a fixed date range
translate_keystringyesDisplay mode in the UI: connection_period (relative date) or connection_range (fixed range)

* Either sub_days or the start_date + end_date pair is required. When both are present, sub_days takes priority.

Two time range modes ​

Mode 1: Relative date (sub_days) ​

The user provides a number of days back from today. The range is calculated dynamically each time the rule executes.

json
{
  "sub_days": 30,
  "translate_key": "connection_period"
}

UI displays: "Last 30 days"

When to use: whenever the user says "last N days", "over the past month", "in the last 90 days", etc.

Mode 2: Fixed date range (start_date + end_date) ​

The user provides specific dates — the range is fixed and does not change over time.

json
{
  "start_date": "2025-01-01",
  "end_date": "2025-03-31",
  "translate_key": "connection_range"
}

UI displays: "2025-01-01 – 2025-03-31"

When to use: when the user provides specific dates, e.g. "from January 1 to March 31, 2025".


Available Analytics Columns ​

paramMetricAllowed operators
google_ads_impressionsImpressions>, <, =, !=, >=, <=, is_empty, not_empty
google_ads_clicksClicks>, <, =, !=, >=, <=, is_empty, not_empty
google_ads_costCost>, <, =, !=, >=, <=, is_empty, not_empty
google_ads_avg_cpcAverage CPC>, <, =, !=, is_empty, not_empty
google_ads_conversionsConversions>, <, =, !=, is_empty, not_empty
google_ads_conv_rateConversion rate>, <, =, !=, is_empty, not_empty
google_ads_total_conv_valueTotal conversion value>, <, =, !=, is_empty, not_empty
google_ads_cost_per_conversionCost per conversion>, <, =, !=, is_empty, not_empty
google_ads_roasROAS>, <, =, !=, is_empty, not_empty

Google Analytics 4 (project_connection_id → connection of type GOOGLE_ANALYTICS_4) ​

Data available from GA4: sessions, revenue, users, cart, orders, and more — depending on the client's GA4 configuration.

Microsoft Ads (project_connection_id → connection of type BING_ADS) ​

Analogous metrics to Google Ads: impressions, clicks, cost, conversions, etc.


How the Filter Is Displayed in the UI ​

The frontend (analytics-picker.component.ts) reads sub_days, start_date, end_date from the filter and displays:

sub_days set        → "Last 30 days"                          ← CORRECT view
sub_days = null and no start_date/end_date → "{{startDate}} - {{endDate}}"  ← INCORRECT view (unresolved template variables)
start_date + end_date set → "2025-01-01 – 2025-03-31"

When AI creates a rule without sub_days and without start_date/end_date — the UI shows raw translation template variables, signaling that the time range data is missing.


Expected System Behavior ​

Step 1 — Intent identification ​

When the user provides a command with an analytics filter, the AI must extract:

  • Metric → param (e.g. "Google Ads conversions" → google_ads_conversions)
  • Operator → symbol (e.g. "greater than" → >, "less than" → <, "equal to" → =)
  • Threshold value → value (e.g. 5)
  • Time range → sub_days or start_date/end_date (e.g. "last 30 days" → sub_days: 30)
  • Platform → connection type (e.g. "Google Ads" → GOOGLE_ADS)

Step 2 — Asking for missing data ​

If the user did not provide a time range — the AI MUST ask before creating the rule.

Example AI question to the user:

"What time period would you like to check the data for? You can provide:— a number of days back (e.g. last 30 days, 90 days)— a specific date range (e.g. from 2025-01-01 to 2025-03-31)"

Creating a rule with a default range without asking is not allowed — the user must consciously make this decision, as the time range directly affects which products will be labeled.

Step 3 — Identifying the project connection ​

The AI must know the project_connection_id — the ID of the specific advertising account in the project.

If the AI does not know the ID:

  1. It calls a tool that lists available project connections for the given platform
  2. If there is exactly one connection of that type — it uses it automatically
  3. If there are multiple connections — it presents the list and asks the user which one to select

Step 4 — Building the complete filter ​

The AI calls the create_product_rule tool with the complete filter:

json
{
  "filterGroups": [
    {
      "filters": [
        {
          "param": "google_ads_conversions",
          "symbol": ">",
          "value": 5,
          "project_connection_id": 123,
          "sub_days": 30,
          "translate_key": "connection_period"
        }
      ]
    }
  ],
  "action": {
    "action": "override",
    "param": "custom_label_0",
    "value": "Marketer"
  },
  "active": true
}

Correctness rules:

  • For relative date: sub_days (integer > 0) + translate_key: "connection_period"
  • For fixed range: start_date + end_date (format YYYY-MM-DD) + translate_key: "connection_range"
  • The symbol field must contain one of the allowed operators — it must never be empty
  • The project_connection_id field is always required

Step 5 — Confirmation before saving ​

Before sending the request to the API, the AI presents the user with a summary of the rule being created and waits for confirmation:

"Creating the rule:— Condition: Google Ads conversions > 5 (last 30 days, account: Sklep PL)— Action: set custom label 0 = 'Marketer'Do you confirm?"


Known Issues and Required Fixes ​

Issue 1 — Missing sub_days in the created filter ​

Symptom: The UI displays - instead of e.g. "Last 30 days".

Cause: The MCP tool (create_product_rule in sembot_public-mcp) does not pass the sub_days field to the API, even when the user provided a relative range.

Required fix:

  • Add the sub_days field (integer) to the MCP tool schema in the filter definition
  • Add the instruction: for relative dates, use sub_days + translate_key: "connection_period", not start_date/end_date

Issue 2 — Missing translate_key in the filter ​

Symptom: The UI does not know in which mode to display the date range button.

Required fix: Always send translate_key with analytics filters (connection_period or connection_range).

Issue 3 — Missing symbol operator ​

Symptom: Filter created without an operator or with an incorrect field name.

Cause: The operator field in the API is called symbol (not operator). The AI may use the wrong name.

Required fix: In the MCP tool schema, the filter operator field must be named symbol with an enum of allowed values: >, <, =, !=, >=, <=, is_empty, not_empty.

Issue 4 — AI does not ask about the time range when data is missing ​

Symptom: The AI creates a rule without asking about the range, resulting in an incomplete filter.

Required fix: Add an instruction to the agent's system prompt or the MCP tool description: before calling create_product_rule with an analytics filter, always ensure you have the time range — if the user did not provide it, ask.