Skip to content

Update URL filter matching guidance for Points and Campaign page visits - #919

Open
promptless-for-oss wants to merge 2 commits into
mautic:7.2from
Promptless:promptless/pr-15979-url-filter-substring-matching
Open

Update URL filter matching guidance for Points and Campaign page visits#919
promptless-for-oss wants to merge 2 commits into
mautic:7.2from
Promptless:promptless/pr-15979-url-filter-substring-matching

Conversation

@promptless-for-oss

Copy link
Copy Markdown
Contributor

Open in Promptless

Mautic 7 (via mautic/mautic PR #15979) unifies how URL filters match across page-related flows. Plain text you enter in a URL filter now matches anywhere within the visited URL as a case-insensitive substring — the same behavior as email click decisions — instead of requiring an exact match or a shell wildcard. Legacy wildcard patterns such as https://example.com* are still supported, so existing saved filters keep working.

Two troubleshooting passages documented the old wildcard-only behavior and are now inaccurate. This corrects them:

  • docs/points/points_troubleshooting.rst — the "Page visits not recognized" item for the Points 'Visits specific URL' action.
  • docs/campaigns/troubleshooting_campaigns.rst — the URL-matching item for the Campaign 'Visits a Page' decision (the A/B query-parameter example, which relies on wildcards, is retained since wildcards still work).

Trigger Events

Mautic PR #15979 unifies URL filter matching so plain text now matches
anywhere in the visited URL as a case-insensitive substring across the
Points 'Visits specific URL' action and the Campaign 'Visits a Page'
decision. Correct the troubleshooting guidance that said a plain URL only
matches exactly or requires a wildcard; note legacy wildcard patterns are
still supported.
@RCheesley RCheesley added this to the Mautic 7.2 milestone Aug 14, 2026
RCheesley
RCheesley previously approved these changes Aug 14, 2026

@RCheesley RCheesley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GTG from my side!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Mautic user documentation to reflect Mautic 7’s unified URL filter behavior for page-related flows: user-entered URL filter text now matches anywhere in the visited URL as a case-insensitive substring, while legacy wildcard patterns (e.g., trailing *) remain supported for prefix-style matching.

Changes:

  • Updates Points troubleshooting guidance for “Visits specific URL” to describe substring, case-insensitive matching and retained wildcard support.
  • Updates Campaign troubleshooting guidance for “Visits a Page” to describe the same matching behavior and clarifies the existing query-parameter/wildcard example.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
docs/points/points_troubleshooting.rst Updates URL matching guidance for Points “Page visits not recognized” troubleshooting.
docs/campaigns/troubleshooting_campaigns.rst Updates URL matching guidance for Campaign “Page visits aren’t recognized” troubleshooting, keeping wildcard examples.
Suppressed comments (1)

docs/campaigns/troubleshooting_campaigns.rst:23

  • "anchors a required prefix" is a bit misleading in the context of wildcard matching; the behavior being described is a prefix match based on the text before the trailing *. Rewording helps avoid implying regex-style anchors.
Another example is if you want to associate different page hits with specific Campaigns. For example, if you have Campaign A and Campaign B and you want to use the same base URL and path for both Campaigns but differentiate with a query parameter. Here the trailing ``*`` anchors a required prefix, so each decision matches only its intended query parameter. For Campaign A, you can define a Visits a Page decision with ``https://example.com/my-page?utm_campaign=A*`` and for Campaign B, ``https://example.com/my-page?utm_campaign=B*``. A Contact only triggers the specific Campaign desired. If the goal is to trigger both Campaigns regardless of the query parameters, use ``https://example.com/my-page*``.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

#. Mautic executes Campaigns sequentially and won't repeat per Contact. If the Contact has already visited the Page while part of the Campaign and triggered the Visits a Page decision, then the Contact's subsequent visits won't re-trigger the actions associated with the decision.

#. Ensure that the URL in the Campaign action either matches exactly the URL visited, or use a wildcard. A URL can include the schema, host/domain, path, query parameters, and/or fragment. For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the Campaign decision won't trigger. However, if you use ``https://example.com*`` as the URL, it matches the rule and thus gets triggered.
#. Ensure that the URL in the Campaign decision appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. The Campaign decision triggers whenever that text appears. A URL can include the scheme, host or domain, path, query parameters, or fragment.
Comment thread docs/points/points_troubleshooting.rst Outdated
2. The tracking of Point Actions is currently done once per Contact. This means that subsequent visits won't re-trigger the action if already triggered once.

3. Ensure that the URL defined either matches exactly the URL visited or use a wildcard. A URL can include the schema, host/domain, path, query parameters, and/or fragment.
3. Ensure that the URL you define appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. The Point Action triggers whenever that text appears. A URL can include the scheme, host or domain, path, query parameters, or fragment.
@RCheesley

Copy link
Copy Markdown
Member

@promptless-for-oss please review the feedback from copilot, can we be clearer in this case?

@promptless-for-oss

Copy link
Copy Markdown
Contributor Author

Thanks @RCheesley — taking a look at Copilot's feedback now and reworking the wildcard/prefix-matching wording so it's clearer and doesn't imply regex-style anchoring. I'll follow up here with the updates.

@promptless-for-oss

Copy link
Copy Markdown
Contributor Author

Reviewed Copilot's feedback — three wording points across the campaigns and points troubleshooting pages: the trailing-* explanation reading like regex anchoring rather than a plain prefix match, and the "whenever that text appears" phrasing that could imply repeat triggering. All are wording-only clarity fixes; no change to the documented behavior. Editing both files now for consistency.

Address GitHub Copilot review points on PR mautic#919:
- Reword the trailing `*` guidance so it describes a prefix match on
  the literal text before it, not a regex-style anchor.
- Reword the URL-condition sentences so they read as the matching
  condition being satisfied, not as repeat/per-visit triggering, keeping
  them consistent with the once-per-Contact behavior stated earlier.
2. The tracking of Point Actions is currently done once per Contact. This means that subsequent visits won't re-trigger the action if already triggered once.

3. Ensure that the URL defined either matches exactly the URL visited or use a wildcard. A URL can include the schema, host/domain, path, query parameters, and/or fragment.
3. Ensure that the URL you define in the Point Action appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. If that text appears in the visited URL, it satisfies the Point Action's URL condition. The once-per-Contact behavior noted earlier still applies, so subsequent visits won't re-trigger it. A URL can include the scheme, host or domain, path, query parameters, or fragment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR mautic/mautic#15979 routes the Point Action "Visits specific URL" filter through UrlMatcher::hasMatch(), which uses preg_match('/'.preg_quote($url,'/').'/i', ...) — a case-insensitive substring match anywhere in the visited URL, confirming "Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive."

Source: https://github.com/mautic/mautic/blob/77f37190aa138c733cdf0a200f1f2f039f89ea61/app/bundles/EmailBundle/Helper/UrlMatcher.php#L27

3. Ensure that the URL you define in the Point Action appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. If that text appears in the visited URL, it satisfies the Point Action's URL condition. The once-per-Contact behavior noted earlier still applies, so subsequent visits won't re-trigger it. A URL can include the scheme, host or domain, path, query parameters, or fragment.

For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the point action won't be recognized. However, if you use ``https://example.com*`` as the URL, it matches the rule and thus gets triggered. No newline at end of file
For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the Point Action now triggers, because the defined text appears in the visited URL. Legacy wildcard patterns such as ``https://example.com*`` are also supported, and a trailing ``*`` still matches any visited URL that begins with the literal text before it. No newline at end of file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR mautic/mautic#15979: UrlMatcher::hasMatch() checks isLegacyWildcardPattern($url) (true when the filter contains , ?, or [) and calls fnmatch($url, $urlToFind, FNM_CASEFOLD) before falling back to substring match. This confirms both that a defined URL of https://example.com now matches https://example.com/index.php?foo=bar via substring matching, and that legacy wildcard patterns like https://example.com remain supported with the trailing * still requiring a literal prefix.

Source: https://github.com/mautic/mautic/blob/77f37190aa138c733cdf0a200f1f2f039f89ea61/app/bundles/EmailBundle/Helper/UrlMatcher.php#L23

#. Mautic executes Campaigns sequentially and won't repeat per Contact. If the Contact has already visited the Page while part of the Campaign and triggered the Visits a Page decision, then the Contact's subsequent visits won't re-trigger the actions associated with the decision.

#. Ensure that the URL in the Campaign action either matches exactly the URL visited, or use a wildcard. A URL can include the schema, host/domain, path, query parameters, and/or fragment. For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the Campaign decision won't trigger. However, if you use ``https://example.com*`` as the URL, it matches the rule and thus gets triggered.
#. Ensure that the URL in the Campaign decision appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. If that text appears in the visited URL, it satisfies the decision's URL condition. The once-per-Contact behavior noted earlier still applies, so subsequent visits won't re-trigger it. A URL can include the scheme, host or domain, path, query parameters, or fragment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR mautic/mautic#15979 changes the Campaign "Visits a Page" decision's URL/Referrer matching from fnmatch() to UrlMatcher::hasMatch($limitToUrls, $pageUrl), which performs a case-insensitive substring match anywhere in the visited URL, confirming "Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive."

Source: https://github.com/mautic/mautic/blob/77f37190aa138c733cdf0a200f1f2f039f89ea61/app/bundles/PageBundle/EventListener/CampaignSubscriber.php#L212

#. Ensure that the URL in the Campaign decision appears somewhere in the visited URL. Mautic matches the URL you enter anywhere within the visited URL, and the match isn't case-sensitive. If that text appears in the visited URL, it satisfies the decision's URL condition. The once-per-Contact behavior noted earlier still applies, so subsequent visits won't re-trigger it. A URL can include the scheme, host or domain, path, query parameters, or fragment.

Another example is if you want to associate different page hits with specific Campaigns. For example, if you have Campaign A and Campaign B and you want to use the same base URL and path for both Campaigns but differentiate with a query parameter. For Campaign A, you can define a Visits a Page decision with ``https://example.com/my-page?utm_campaign=A*`` and for Campaign B, ``https://example.com/my-page?utm_campaign=B*``. A Contact only triggers the specific Campaign desired. If the goal is to trigger both Campaigns regardless of the query parameters, use ``https://example.com/my-page*``. No newline at end of file
For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the Campaign decision now triggers, because the defined text appears in the visited URL. Legacy wildcard patterns such as ``https://example.com*`` are also supported, and a trailing ``*`` still matches any visited URL that begins with the literal text before it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR mautic/mautic#15979: UrlMatcher::hasMatch() now matches a defined URL of https://example.com against a page hit of https://example.com/index.php?foo=bar as a substring (previously required a wildcard), and isLegacyWildcardPattern()/fnmatch(..., FNM_CASEFOLD) preserves legacy wildcard patterns such as https://example.com*, with a trailing * still anchoring a required literal prefix.

Source: https://github.com/mautic/mautic/blob/77f37190aa138c733cdf0a200f1f2f039f89ea61/app/bundles/EmailBundle/Helper/UrlMatcher.php#L23

Another example is if you want to associate different page hits with specific Campaigns. For example, if you have Campaign A and Campaign B and you want to use the same base URL and path for both Campaigns but differentiate with a query parameter. For Campaign A, you can define a Visits a Page decision with ``https://example.com/my-page?utm_campaign=A*`` and for Campaign B, ``https://example.com/my-page?utm_campaign=B*``. A Contact only triggers the specific Campaign desired. If the goal is to trigger both Campaigns regardless of the query parameters, use ``https://example.com/my-page*``. No newline at end of file
For example, if you have a URL of ``https://example.com`` and the page hit registers as ``https://example.com/index.php?foo=bar``, the Campaign decision now triggers, because the defined text appears in the visited URL. Legacy wildcard patterns such as ``https://example.com*`` are also supported, and a trailing ``*`` still matches any visited URL that begins with the literal text before it.

Another example is if you want to associate different page hits with specific Campaigns. For example, if you have Campaign A and Campaign B and you want to use the same base URL and path for both Campaigns but differentiate with a query parameter. Here the trailing ``*`` matches any visited URL that begins with the literal text before it, so each decision matches only its intended query parameter. For Campaign A, you can define a Visits a Page decision with ``https://example.com/my-page?utm_campaign=A*`` and for Campaign B, ``https://example.com/my-page?utm_campaign=B*``. A Contact only triggers the specific Campaign desired. If the goal is to trigger both Campaigns regardless of the query parameters, use ``https://example.com/my-page*``. No newline at end of file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR mautic/mautic#15979: isLegacyWildcardPattern() (strpbrk($url, '?[')) routes any filter containing * to fnmatch() instead of substring matching, so trailing- patterns like https://example.com/my-page?utm_campaign=A* still anchor a required literal prefix, letting Campaign A and Campaign B differentiate by query parameter.

Source: https://github.com/mautic/mautic/blob/77f37190aa138c733cdf0a200f1f2f039f89ea61/app/bundles/EmailBundle/Helper/UrlMatcher.php#L61-L63

@promptless-for-oss

Copy link
Copy Markdown
Contributor Author

Thanks — good catch. We've reworded the flagged guidance in both troubleshooting pages (docs/campaigns/troubleshooting_campaigns.rst and docs/points/points_troubleshooting.rst):

  • The trailing * is now described as a simple prefix match on the literal text before it, rather than "anchoring a prefix" (which could read as a regex-style anchor).
  • The URL-matching sentences now describe when the match condition is met and explicitly point back to the once-per-Contact behavior, so they can't be misread as re-triggering on every visit.

Vale passes on both files. The changes are pushed (SHA b91604e6) and ready for another look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants