A page visit goal counts a visit when it opens a page whose address matches your rule. It is perfect for thank-you pages, confirmations and important content. In the dashboard, this goal type is called A page visit. No code is needed.
The same address rules also apply to A click on a link goals and to page steps in funnels.
When to use page visit goals
Best for tracking:
- Thank-you pages after forms
- Purchase confirmation pages
- Registration complete pages
- Important content pages, like your pricing page
- Download confirmation pages
Creating a page visit goal
Open the Goals sub-tab
Open your website from Domains, select the Journeys tab, then the Goals sub-tab, and click New goal.
Choose A page visit
In the first step, choose A page visit. The templates Sign-ups, Contact form and Pricing page visits also create page visit goals.
Pick the page
Pick the page from the list of your pages, or type its address. Choose a match type if you need more than one page.
Check the live preview
The preview shows how many pages and visits match in the selected period.
Name and value
Give the goal a name. Optionally turn on Give each conversion a value. Leave Count past visits too on to count the last 12 months right away.
Save
Click Create goal.
The page picker
In the second step, the assistant lists the real pages of your site that had visits in the selected period, with their view counts. Search the list and click a page to use its address.
- Include every language version: on a multi-language site, switch this on to count every language version of a page.
/en/pricingbecomes/{locale}/pricing, so/de/pricing,/fr/pricingand so on count too. - Several hosts: if your site has more than one host (for example
example.comanddocs.example.com), the picker keeps the host, so the goal only counts that host. - Live preview: shows "Matches N pages with X visits in the selected period". If nothing matches, Zenovay suggests similar real pages, so a typo is easy to spot.
Match types
| Match type | Use it for |
|---|---|
| Is exactly | One specific page |
| Starts with | A whole section, like /blog/ |
| Contains | Addresses that share a word, including the query string |
| Ends with | Pages that share an ending, like /success |
| Matches a pattern | Several pages with one simple rule, like every language version |
| Regular expression (advanced) | Complex rules, if the other options are not enough |
Is exactly
| Setting | Value |
|---|---|
| Match type | Is exactly |
| Pattern | /thank-you |
| Matches | example.com/thank-you, example.com/Thank-You/ |
| Doesn't match | example.com/thank-you/order |
Starts with
| Setting | Value |
|---|---|
| Match type | Starts with |
| Pattern | /blog/ |
| Matches | /blog/post-1, /blog/category/news |
| Doesn't match | /about/blog |
Contains
| Setting | Value |
|---|---|
| Match type | Contains |
| Pattern | thank |
| Matches | /thank-you, /thanks, /order/thank-you |
Contains also searches the query string. So utm_source=newsletter counts visits that opened a page with that parameter.
Ends with
| Setting | Value |
|---|---|
| Match type | Ends with |
| Pattern | /success |
| Matches | /payment/success, /signup/success |
| Doesn't match | /success/details |
Matches a pattern
A pattern is an address with placeholders:
| Placeholder | Stands for |
|---|---|
* | Exactly one part of the path (between two slashes) |
** | Anything, including several parts |
{locale} | An optional language prefix, such as /en, /de or /pt-BR |
| Pattern | Matches | Doesn't match |
|---|---|---|
/{locale}/pricing | /pricing, /en/pricing, /pt-BR/pricing | /pricing/enterprise |
/blog/* | /blog/my-post | /blog/2026/my-post |
/blog/** | /blog/my-post, /blog/2026/my-post | /news/my-post |
/order/*/confirmed | /order/1234/confirmed | /order/confirmed |
Regular expression (advanced)
Matches with a regular expression. It is compared without regard to upper and lower case. Patterns that could run forever are rejected. Only use this if the other options are not enough.
| Pattern | Matches |
|---|---|
/order/\d+ | /order/123, /order/456789 |
\.(pdf|doc)$ | Addresses ending in .pdf or .doc |
^/products?/ | /product/ or /products/ |
How addresses are compared
These rules apply to every match type:
| Part of the address | Does it matter? |
|---|---|
| Upper and lower case | Never: /Thank-You is the same as /thank-you |
| A trailing slash | Never: /pricing/ is the same as /pricing |
www. | Never: www.example.com is the same as example.com |
#anchors | Never: /pricing#faq is the same as /pricing |
Query string (?ref=email) | Only if your pattern contains a ?. Contains also searches it |
Host (docs.example.com) | Only if your pattern starts with a host |
Restricting a goal to one host
A pattern may start with a host, for example docs.example.com/intro. Then only that host counts. Without a host, the pattern matches every host of your site.
Query parameters
By default, the query string is ignored: /thank-you also counts /thank-you?ref=email. To count only visits with a specific parameter, put it in your pattern:
| Pattern | Match type | Counts |
|---|---|---|
/success?source=paid | Is exactly | Only the success page reached with source=paid |
utm_campaign=spring | Contains | Any page opened from your spring campaign links |
Common examples
E-commerce
| Goal | Pattern | Match type |
|---|---|---|
| Purchase complete | /order/confirmation | Is exactly |
| Any order page | /order/ | Starts with |
| Cart page | /cart | Is exactly |
Lead generation
| Goal | Pattern | Match type |
|---|---|---|
| Contact form thanks | /contact/thank-you | Is exactly |
| Any form completion | thank-you | Contains |
| Demo scheduled | /demo/confirmed | Is exactly |
Content sites
| Goal | Pattern | Match type |
|---|---|---|
| Article read | /blog/ | Starts with |
| Guide download | /guides/ | Starts with |
| Pricing in every language | /{locale}/pricing | Matches a pattern |
SaaS
| Goal | Pattern | Match type |
|---|---|---|
| Sign-up complete | /welcome | Is exactly |
| Upgrade success | /upgrade/success | Is exactly |
Handling variations
Several thank-you pages
Option 1: use Contains
- Pattern
thankmatches all of them
Option 2: create one goal per page
- Goal 1:
/contact/thanks - Goal 2:
/signup/thanks
Option 3: use Matches a pattern
- Pattern
/*/thanksmatches/contact/thanksand/signup/thanks
Addresses with changing parts
For addresses that contain an id or a name, Matches a pattern is usually the easiest choice:
| Address | Pattern |
|---|---|
/order/12345 | /order/* |
/user/john-doe | /user/* |
/shop/shoes/blue-sneaker | /shop/** |
Past visits
A new page visit goal counts the last 12 months of your data right away, as long as Count past visits too is on. If you later change the address or the match type, Zenovay recounts the last 12 months with the new rule (switch Recount past visits with the new rule). The previous numbers are archived, not lost.
Single page apps (SPAs)
For SPAs with client-side routing:
- Zenovay tracks route changes
- Works with React Router, Vue Router and similar
- Routes that only differ after a
#count as the same page, because#anchorsnever matter in address matching. If your app uses hash routing (/#/pricing), use an event goal instead
SPA tracking is built in. Zenovay detects route changes via the History API (pushState, replaceState, popstate). No extra setup is needed.
Some SPAs need a manual page view:
// When the route changes
zenovay('page');
Troubleshooting
The goal is not counting
Check the rule:
- Open the goal's details and look at Pages this goal counts
- Edit the goal and look at the live preview and the suggested pages
- Check the match type
Check the page:
- Is the tracking script installed on that page?
- Does the page appear in your analytics?
Test it yourself:
- Open the page
- Check the Live View tab
Too many pages match
- Use Is exactly instead of Contains
- Add more of the path, or use Matches a pattern
- Restrict the goal to one host by starting the pattern with it
Fewer pages match than expected
- Upper and lower case, trailing slashes,
www.and anchors never matter, so you don't need extra goals for them - If your pattern contains a
?, the query string must match too. Remove it, or use Contains - Check the syntax of a regular expression
Best practices
Be specific
| Too broad | Better |
|---|---|
thank | /checkout/thank-you |
success | /signup/success |
Test before you rely on it
- Create the goal
- Check the live preview
- Open the page yourself
- Check the goal's Latest conversions
Describe your goals
Use the description field to note what the goal measures and why, so your team knows what each number means.