Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contents/blog/what-is-a-feature-flag.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ In PostHog, feature flags support percentage-based rollouts (ship to 5% of users

- **Progressive rollouts** – Ship to a small group, monitor for issues, then expand. This is the classic [canary release](/tutorials/canary-release) pattern.
- **Kill switches** – Instantly disable a broken feature without rolling back a deployment. No hotfix, no deploy, no waiting.
- **Internal testing** – Release to your team first (set email contains `@yourcompany.com`), then to beta users, then to everyone.
- **Internal testing** – Release to your team first (set email ends with `@yourcompany.com`), then to beta users, then to everyone.
- **Operational toggles** – Maintenance mode, circuit breakers, or infrastructure controls that stay permanent.

[Feature flags have a lot of uses](/product-engineers/feature-flag-benefits-use-cases), but measuring impact isn't one of them. They let you turn something on and off, but, on their own they won't tell you whether "on" is actually good. That's when you pair them with [analytics](/docs/product-analytics) and [experiments](/docs/experiments).
Expand Down
6 changes: 4 additions & 2 deletions contents/docs/data/cohorts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ You can use cohorts to answer questions like:

Cohorts are sometimes confused with [groups](/docs/product-analytics/group-analytics), but they each serve different purposes:

- **Cohorts** represent a specific set of users – e.g., a list of users whose email contains a certain string (like a company's domain).
- **Cohorts** represent a specific set of users – e.g., a list of users whose email ends with a certain string (like a company's domain).

- **Groups** aggregate events based on entities, such as organizations or companies, but do not necessarily connect to a user. They enable you to analyze trends, insights, and dashboards at an entity-level (like a company or organization), as opposed to a user-level.

Expand Down Expand Up @@ -267,7 +267,9 @@ Has or doesn't have a person property with the following operators:
| **Operator** | **Example** |
| -------------------------------------------- | --------------------------------------------------------------- |
| `equals` or `does not equal` | `Pineapple on pizza` property `does not equal` "true" |
| `contains` or `does not contain` | `email` property `does not contain` "gmail", "yahoo", "hotmail" |
| `contains` or `does not contain` | `Job title` property `contains` "engineer" |
| `starts with` or `does not start with` | `$initial_current_url` property `starts with` "https://app." |
| `ends with` or `does not end with` | `email` property `does not end with` "@gmail.com", "@yahoo.com", "@hotmail.com" |
| `matches regex` or `does not match regex` | `Country code` property `matches regex` "us\|uk\|aus" |
| `greater than` or `greater than or equal to` | `Age` property `greater than` "21" |
| `less than` or `less than or equal to` | `Age` property `less than or equal to` "21" |
Expand Down
4 changes: 4 additions & 0 deletions contents/docs/data/property-filters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ String operators work on text-based properties. These are the most common operat
|----------|-------------|
| `exact` / `is not` | Matches when the property value equals (or does not equal) any value in the list |
| `contains` / `does not contain` | Matches when the property value contains (or does not contain) the substring |
| `starts with` / `does not start with` | Matches when the property value starts (or does not start) with the substring |
| `ends with` / `does not end with` | Matches when the property value ends (or does not end) with the substring |
| `matches regex` / `does not match regex` | Matches when the property value matches (or does not match) a regular expression |

> **Tip:** To target by email domain, use `ends with` instead of `contains`. For example, `email contains @posthog.com` also matches `bad-person@posthog.computer.com`, while `email ends with @posthog.com` only matches addresses on that exact domain.

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.

Is this how our contains logic works, it matches even if the string is split?

Suggested change
> **Tip:** To target by email domain, use `ends with` instead of `contains`. For example, `email contains @posthog.com` also matches `bad-person@posthog.computer.com`, while `email ends with @posthog.com` only matches addresses on that exact domain.
> **Tip:** To target by email domain, use `ends with` instead of `contains`. For example, `email contains posthog.com` also matches `bad-person@computer.posthog.com`, while `email ends with @posthog.com` only matches addresses on that exact domain.

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.

I'm not sure what you mean by the string is split.

If you're matching "contains '@posthog.com'" it means the string contains @posthog.com anywhere in the string.

bad-person@posthog.computer.com contains @posthog.com

bad-person-->@posthog.com<--puter.com


String properties also support [semver operators](#semver-operators) for comparing version strings like `1.2.3`. These appear alongside the regular string operators in the filter dropdown.

## Numeric operators
Expand Down
4 changes: 2 additions & 2 deletions contents/docs/feature-flags/canary-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ Beyond testing the flag yourself, here is a recommended step-by-step release wit

1. **Just yourself:** set email to equal to your own, like `email equals ian@posthog.com`. Test it yourself to make sure the feature flag works and the feature works as expected.

2. **Internal team:** set email to contain your domain, like `email contains posthog.com` or `email equals <insert multiple team member emails>`. This enables [testing in production](/product-engineers/testing-in-production). Make sure to communicate with your team about what is being released so they know to test and look out for issues.
2. **Internal team:** set email to end with your domain, like `email ends with @posthog.com` or `email equals <insert multiple team member emails>`. This enables [testing in production](/product-engineers/testing-in-production). Make sure to communicate with your team about what is being released so they know to test and look out for issues.

3. **Beta users, organizations:** [use early access management](/docs/feature-flags/early-access-feature-management), set email to contain a company domain, or set the group name to equal theirs, like `email contains twitter.com` or `organization_name equals twitter`. To ensure you are aware of issues, communicate with them and monitor a related usage dashboard.
3. **Beta users, organizations:** [use early access management](/docs/feature-flags/early-access-feature-management), set email to end with a company domain, or set the group name to equal theirs, like `email ends with @twitter.com` or `organization_name equals twitter`. To ensure you are aware of issues, communicate with them and monitor a related usage dashboard.

4. **Expanded beta:** set release to a percentage of users or to match a popular property. Monitor insights and sessions related to the feature compared to those without. The overall metrics are more important here.

Expand Down
2 changes: 2 additions & 0 deletions contents/docs/feature-flags/creating-feature-flags.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ Rollout percentages support decimal values with up to two decimal places of prec

- If the property you want to target lives in another system, like a plan tier in Stripe or a lifecycle stage in Salesforce, sync that table into the [data warehouse](/docs/data-warehouse) and map it onto person or group properties with [warehouse properties](/docs/data-warehouse/warehouse-properties). Flags can then target it like any other property. A [join](/docs/data-warehouse/join) does not work here, because flags evaluate against stored properties rather than at query time.

> **Tip:** To target your team by email domain, use the `ends with` operator (like `email ends with @posthog.com`) rather than `contains`, which also matches lookalike domains like `posthog.computer.com`. See [property filter operators](/docs/data/property-filters#string-operators) for the full list.

When you target a person property of `distinct_id equals`, the value field searches persons by name, email, or distinct_id, so you don't need to paste a raw ID. A person with multiple distinct_ids – for example an anonymous device ID plus an identified email – appears as a separate option per ID, so you can pick the specific one the SDK captures under. The stored filter value is still the literal distinct_id, so flag evaluation is unchanged.

<ProductScreenshot
Expand Down
2 changes: 1 addition & 1 deletion contents/docs/feature-flags/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ This occurs because the `in` and `not_in` operators are reserved for **cohort pr

### What operators should I use instead?

For person or group properties, use any of the [string, numeric, presence, or semver operators](/docs/data/property-filters). For example: `exact`, `contains`, `regex`, `is set`, or any of the semver operators for version-based targeting.
For person or group properties, use any of the [string, numeric, presence, or semver operators](/docs/data/property-filters). For example: `exact`, `contains`, `starts with`, `ends with`, `regex`, `is set`, or any of the semver operators for version-based targeting.

For cohort targeting, use the cohort property type with `in` or `not_in` operators to target users who are or aren't members of a specific cohort.

Expand Down
8 changes: 6 additions & 2 deletions contents/docs/product-analytics/trends/filters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Some common operators used in insight filters:
| ≠ doesn't equal | The property _doesn't_ exactly match any of the values you provided |
| ∈ contains | The property contains the value as a substring and can contain multiple values to match against |
| ∉ doesn't contain | The property doesn't contain any of the values you provided as a substring |
| ↦ starts with | The property starts with the value as a prefix and can contain multiple values to match against |
| ↛ doesn't start with | The property doesn't start with any of the values you provided as a prefix |
| ⇥ ends with | The property ends with the value as a suffix and can contain multiple values to match against |
| ⇻ doesn't end with | The property doesn't end with any of the values you provided as a suffix |
| ~ matches regex | The property matches a regex _(only available for strings)_ |
| ≁ doesn't match regex | The property doesn't matches a regex _(only available for strings)_ |
| > greater than | The property is greater than a specific value _(only available for numeric properties)_ |
Expand All @@ -92,7 +96,7 @@ For a complete list of all available operators, including numeric range operator

This is the value that PostHog compares to the property using the operation you specified. If the operation returns true, then the event is included in the insight, and if it returns false it is excluded.

Some operations – equals, doesn't equal, contains, and doesn't contain – allow you to pass multiple values to compare against, in which case the event is included if any of these values return true when compared.
Some operations – equals, doesn't equal, contains, doesn't contain, starts with, doesn't start with, ends with, and doesn't end with – allow you to pass multiple values to compare against, in which case the event is included if any of these values return true when compared.

## Types of filters

Expand Down Expand Up @@ -172,4 +176,4 @@ This option finds a user's very first occurrence of an event type, and then chec

This option finds the first time a user performed an event type _that also matches your filters_. Previous events of the same type from that user that don't match the filters are ignored.

**Example:** You're filtering for pageview events to `/about`. A user first visited `/pricing` and then later visited `/about`. PostHog ignores the `/pricing` view and counts the `/about` view, as it's the first one that matches the filter.
**Example:** You're filtering for pageview events to `/about`. A user first visited `/pricing` and then later visited `/about`. PostHog ignores the `/pricing` view and counts the `/about` view, as it's the first one that matches the filter.
8 changes: 4 additions & 4 deletions contents/docs/support/workflows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Use `if/else` blocks in your workflow to branch logic.
event.properties.channel_source = "slack"
event.properties.status = "new"
event.properties.priority = "high"
event.properties.customer_email contains "@enterprise.com"
event.properties.customer_email ends with "@enterprise.com"
event.properties.new_status = "resolved"
event.properties.message_content contains "urgent"
```
Expand Down Expand Up @@ -290,14 +290,14 @@ Tag tickets from specific customer domains for prioritization.

**Flow:**

1. **If** `event.properties.customer_email` contains `@bigcorp.com`
1. **If** `event.properties.customer_email` ends with `@bigcorp.com`
- **Update ticket:**

```
tags = ["enterprise", "priority"]
```

2. **Else if** `event.properties.customer_email` contains `@startup.io`
2. **Else if** `event.properties.customer_email` ends with `@startup.io`
- **Update ticket:**

```
Expand Down Expand Up @@ -355,7 +355,7 @@ sla_unit = "hour"
assignee = Engineering role
```

3. **Else if** `event.properties.customer_email` contains `@enterprise.com`
3. **Else if** `event.properties.customer_email` ends with `@enterprise.com`
- **Update ticket:**

```
Expand Down
4 changes: 2 additions & 2 deletions contents/tutorials/filter-internal-users.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ Any internal users you identify for a project will apply for _all_ users on that

## Step 2: Add an internal user filter

> **Tip:** Inline person property filters (e.g., "email does not contain your-domain.com") work everywhere, including real-time [CDP](/docs/cdp) destinations. Alternatively, you can [create a cohort](/docs/data/cohorts#method-2-create-a-new-cohort-from-the-cohorts-page) and add it with a "not in" operator – this works well for analytics queries (insights, dashboards) and also works in CDP destinations if the cohort contains **exclusively person property filters**. Cohorts with behavioral filters or no properties defined will cause CDP destinations to error.
> **Tip:** Inline person property filters (e.g., "email does not end with @your-domain.com") work everywhere, including real-time [CDP](/docs/cdp) destinations. Alternatively, you can [create a cohort](/docs/data/cohorts#method-2-create-a-new-cohort-from-the-cohorts-page) and add it with a "not in" operator – this works well for analytics queries (insights, dashboards) and also works in CDP destinations if the cohort contains **exclusively person property filters**. Cohorts with behavioral filters or no properties defined will cause CDP destinations to error.

In project settings, scroll down to the ‘_Filter out internal and test users_’ section and click ‘_+ Add filter_’ to begin.

Adding a filter here works exactly the same as it does when you add a filter to any other insight, with a list of available events, properties, and cohorts to choose from as a base for your filter. You can add several filters at once, to create an inclusive list of ways to identify groups of internal users or beta testers.

One of the easiest filters to create is to filter out internal users identified by their email address. We do this at PostHog, using the following filter to create insights based only on users who do not have a PostHog email address:

> email ∌ (doesn’t contain) @posthog.com
> email ⇻ (doesn’t end with) @posthog.com

<ProductScreenshot
imageLight={step2Light}
Expand Down
Loading