4 · Applications & URL regex
An Application answers "which requests does this policy apply to?" It's built almost
entirely from one HAR field — request.url — plus optionally request.method. A Rule won't
run unless its Application matches the request, so getting this right (precise, but not brittle)
matters.
Anatomy of an Application
| Field | From HAR | Notes |
|---|---|---|
| Name | — | Unique, human-readable. e.g. Contact List HubSpot |
| Definition(s) | request.url |
One or more URL match rules (below) |
| Method | request.method |
Restrict to GET/POST/… or leave empty for all |
| Content Type | request.postData.mimeType / response content.mimeType |
Optionally restrict |
| Behavior | — | Match (apply policy) or Bypass (exempt) |
An Application can be reused across many Rules. For example, a single broad Salesforce GraphQL
Application (acme.my.salesforce.com/services/data/v59.0/graphql) can be shared by many GraphQL
operations — because GraphQL sends everything to one URL, the operation is distinguished in the
Data Type, not the Application.
Definition types (URL match)
Each definition targets a part of the URL. Pick the most specific type that isn't brittle:
| Type | Matches | Example |
|---|---|---|
| Domain | Domain and all subdomains | salesforce.com → acme.my.salesforce.com, na1.salesforce.com |
| Hostname | A specific host (supports * wildcard) |
acme.my.salesforce.com, *.hubapi.com |
| Path | URL path prefix | /crm/v3/objects/contacts |
| Object Part | Any single path segment (substring of the path) | contacts |
| Query String | Substring of the query string | limit= |
| Full URL | Substring of the entire URL | acme.my.salesforce.com/services/apexrest/discount |
| Regex | Regular expression against the full URL | api\.hubapi\.com\/crm\/v3\/objects\/contacts\?.* |
Most custom policies use either Full URL (simple, readable) or Regex (when you need to pin a path and a query parameter, or allow variation).
Regex matches the whole URL string
A Regex definition is tested against the complete URL (scheme + host + path + query). It's
a contains-style test unless you anchor with ^…$. Escape the dots (\.) and the ?
(\?) so they're literal. RE2 syntax — no look-around.
Turning request.url into a match
- Copy the URL from the HAR:
https://api.hubapi.com/crm/v3/objects/contacts?limit=25&archived=false - Decide what's stable vs incidental:
- Host (
api.hubapi.com) and path (/crm/v3/objects/contacts) → stable, keep them. limit=25,archived=false→ values vary; match the parameter name, not the value.- Write the tightest match that still catches every variant:
(A Regex definition. It pins host + path and requires a query string (the list call), but tolerates any limit / paging params.)
- Add the Method if the same path serves different verbs. The contact-list block is
GETonly, so set Method =GETto avoid touching thePOSTthat creates a contact.
Precise but not brittle — the balance
| Too loose | Too tight |
|---|---|
Domain: salesforce.com for a single endpoint → scans every Salesforce subdomain, wastes cycles, risks false hits |
Full URL with limit=25&archived=false hard-coded → breaks the moment paging changes |
Good middle ground: pin host + path, match query parameters by name, ignore their values, and constrain the method. The Data Type does the fine-grained work inside the body; the Application just needs to get the right requests onto the conveyor belt.
GraphQL special case
GraphQL APIs send every operation to the same URL (/graphql). So:
- The Application is broad: a Full URL match on
acme.my.salesforce.com/services/data/v59.0/graphql, methodPOST. - The Data Type does the discrimination via a
ConditiononoperationName(see Custom Data Types).
Don't try to distinguish GraphQL operations in the URL — you can't; they're all the same URL.
Bypass definitions
Behavior = Bypass creates an exemption. Use it to carve a quiet sub-path out of a broad
Match — e.g. Match Domain: company.com but Bypass Hostname: blog.company.com so the public
blog is never scanned. Bypass wins over Match.
Wiring it into a Rule
Once you have an Application (this chapter) and a Custom Data Type (previous chapter), the rest is standard Shield configuration that doesn't depend on the HAR:
- Pick a Mask Format (how the value is transformed).
- Create an Obfuscation pairing the Data Type with that Mask Format.
- Create a Rule — set the Action (Detect / Obfuscate / Block), the
Apply To (Request if the data was in
request.postData, Response if it was inresponse.content), and attach the Application + Obfuscation.
These three objects are documented in the Admin Console docs (Mask Formats · Obfuscations · Rules) and aren't re-explained here.
Next: Full worked example →