GoHighLevel Integration
Connect TrolleyShield to GoHighLevel (GHL) to analyze calls and forms directly from GHL workflows. When installed, two custom workflow actions become available: Analyze Call and Analyze Form.
Phone numbers and number pools are synced automatically from your GHL location. Conversion settings are configured per-workflow, giving you full control over which Google Ads conversions to fire and when.
Requirements
- A paid plan with API access (any Call Shield plan, or Form Pro/Business)
- A GoHighLevel account with workflow access
Setup
1. Install the App
- Go to Settings → Integrations → GoHighLevel in the TrolleyShield dashboard
- Click Connect GoHighLevel
- You'll be redirected to GoHighLevel to select a location
- Authorize TrolleyShield to access your GHL account
- You'll be redirected back to TrolleyShield with a success confirmation
- Phone numbers and number pools are synced automatically on connect
2. Add Workflow Actions
Once connected, two custom actions are available in GHL's workflow builder:
- Open a workflow in GoHighLevel (Automation → Workflows)
- Add a new action step
- Search for TrolleyShield in the action list
- Select Analyze Call or Analyze Form
- Configure the action fields (see below)
- Use IF/ELSE branches on the output variables to route contacts
Workflow Actions
Analyze Call
Analyze a call transcript or recording using TrolleyShield's AI. Creates a full call record in the TrolleyShield dashboard with AI analysis, and optionally fires Google Ads conversions.
GHL's Call Completed trigger does not expose the call transcript or recording URL. You must use the Transcript Generated trigger so the transcript is available to map.
To enable transcriptions in GHL:
- Go to Settings → Phone Numbers → Advanced Settings
- Enable Call Transcriptions under Voice Calls
- On each number, click the three dots → Edit Configuration → enable Call Recording
Transcription is a paid GHL feature (~$0.03/minute on top of call recording).
Input Fields:
| Field | Type | Required | Description |
|---|---|---|---|
| Transcript | textarea | Yes* | Call transcript text. Map to {{transcript_generated.call_transcript}} |
| Recording URL | string | Yes* | URL to audio recording for automatic transcription. Map to {{transcript_generated.recording_url}} |
| Caller Number | string | No | Caller phone number. Map to {{transcript_generated.call_from}} |
| Caller Name | string | No | Caller ID name. Map to {{contact.name}} or {{contact.firstName}} {{contact.lastName}} |
| Called Number | string | No | The number that was called. Map to {{transcript_generated.call_to}}. Used to match against synced tracking numbers |
| Duration (seconds) | number | No | Call duration in seconds. Map to {{transcript_generated.call_duration}} |
| Call Time | string | No | When the call occurred. Map to {{transcript_generated.call_start_time}} |
| External Call ID | string | No | Unique identifier to prevent duplicate processing |
| Landing Page | string | No | The full landing page URL with query string. Map to {{contact.attributionSource.url}}. TrolleyShield parses gclid, gbraid, wbraid, fbclid, msclkid, and all utm_* parameters out of this URL automatically — you do not need to map them individually. |
| Referrer | string | No | Referrer URL. Map to {{contact.attributionSource.referrer}} |
| GA Client ID | string | No | Google Analytics client ID for GA4 session stitching. Map to {{contact.attributionSource.gaClientId}} |
| Call Context | textarea | No | Describe what this tracking number or campaign is for (e.g. "Google Ads campaign for bathroom remodeling leads"). Helps the AI understand what a qualified call looks like for this workflow. Your account-level business description is always included automatically. |
| Conversion Action | dropdown | No | Select a Google Ads conversion action from your connected account |
| Conversion Tags | multi-select | No | Only fire conversions when the AI tags the call with one of these services. Leave empty for any qualifying call. Populated from your service tags. |
| Conversion Value | number | No | Dollar value to report for this conversion |
| Min Confidence | number | No | Minimum AI confidence score to trigger a conversion (default: 80) |
| Min Duration (sec) | number | No | Minimum call duration to trigger a conversion (default: 60) |
* Either Transcript or Recording URL is required.
Hidden Fields (configured once, not visible to workflow users):
| Field | Default Value |
|---|---|
| Location ID | {{location.id}} |
| Contact ID | {{contact.id}} |
Output Variables (available in subsequent workflow steps):
| Variable | Type | Description |
|---|---|---|
intent | string | qualified_lead, general_inquiry, existing_customer, spam, wrong_number, job_seeker, vendor, or incomplete |
confidence | number | AI confidence score (0-100) |
reasoning | string | Explanation of the classification |
action | string | Recommended action: convert, nurture, ignore, or block |
tags | array | Matched service tags (e.g. ["roofing", "gutters"]). Empty if no tags configured. |
transcript_status | string | completed, failed, or pending |
contact_id | string | GHL contact ID (passed through) |
Analyze Form
Analyze a form submission or contact data for spam, bots, and lead quality.
Input Fields:
| Field | Type | Required | Description |
|---|---|---|---|
| Form Data | textarea | No | Full form submission as JSON. Or map individual fields below |
| Name | string | No | Submitter's name. Map to {{contact.name}} |
| string | No | Submitter's email. Map to {{contact.email}} | |
| Phone | string | No | Submitter's phone. Map to {{contact.phone}} |
| Message | textarea | No | Form message or inquiry text |
| Form Name | string | No | Identifies which form triggered the submission (shown in TrolleyShield dashboard) |
| Site URL | string | No | Website where the form was submitted |
| IP Address | string | No | Submitter's IP for spam detection |
| Landing Page | string | No | The full landing page URL with query string. Map to {{contact.attributionSource.url}}. TrolleyShield parses gclid, gbraid, wbraid, fbclid, msclkid, and all utm_* parameters out of this URL automatically — you do not need to map them individually. |
| Referrer | string | No | Referrer URL. Map to {{contact.attributionSource.referrer}} |
| GA Client ID | string | No | Google Analytics client ID for GA4 session stitching. Map to {{contact.attributionSource.gaClientId}} |
| Form Context | textarea | No | Describe what this form is for (e.g. "Roofing quote request form on the commercial services page"). Helps the AI distinguish real leads from spam for this form type. Your account-level business description is always included automatically. |
| Conversion Action | dropdown | No | Select a Google Ads conversion action |
| Conversion Value | number | No | Dollar value for this conversion |
| Min Confidence | number | No | Minimum confidence to trigger a conversion (default: 80) |
You can map GHL contact fields directly instead of using the Form Data JSON field. TrolleyShield will automatically build the form data from all mapped fields. System fields (locationId, contactId) are filtered out automatically.
Hidden Fields:
| Field | Default Value |
|---|---|
| Location ID | {{location.id}} |
| Contact ID | {{contact.id}} |
Output Variables (available in subsequent workflow steps):
| Variable | Type | Description |
|---|---|---|
intent | string | legitimate, spam, bot, phishing, irrelevant, or suspicious |
confidence | number | AI confidence score (0-100) |
reasoning | string | Explanation of the classification |
action | string | Recommended action: allow, flag, or block |
tags | array | Matched service tags (e.g. ["bathroom", "interior"]). Empty if no tags configured. |
contact_id | string | GHL contact ID (passed through) |
Phone Number Sync
TrolleyShield automatically syncs phone numbers and number pools from your connected GHL location:
- On connect: All numbers and pools are imported automatically
- Manual sync: Click "Sync Numbers" in Settings → Integrations → GoHighLevel
- Auto-sync on unknown number: When a call comes in on a number not yet in TrolleyShield, a re-sync is triggered automatically
- Auto-create: If a number still isn't found after re-sync, it's created as a new GHL tracking number
Number pools are stored as a single tracking number with all pool numbers tracked in metadata. When any pool number receives a call, it matches to the correct pool.
Synced numbers appear in the Numbers page with GHL or GHL Pool badges. These numbers are read-only in TrolleyShield — they're managed by the GHL sync.
Conversion Tracking
Conversion settings are configured per-workflow in GHL, not in TrolleyShield:
- Select a Conversion Action from the dropdown (loaded from your connected Google Ads account)
- Set a Conversion Value (e.g. $50 for a contact form, $200 for a quote request)
- Set Min Confidence and Min Duration thresholds
Priority order (first non-empty value wins):
- Workflow action fields
- Tracking number settings (if configured in TrolleyShield)
- Account defaults
Conversions are queued when:
- AI classifies the call/form as qualifying (e.g.
intent = qualified_leadfor calls,intent = legitimatefor forms) - Confidence meets the minimum threshold
- Duration meets the minimum (calls only)
- A GCLID, GBRAID, or WBRAID is present for attribution
Example Workflows
Call Analysis with Conversion Tracking
Trigger: Transcript Generated
→ TrolleyShield: Analyze Call
transcript: {{transcript_generated.call_transcript}}
caller_number: {{transcript_generated.call_from}}
called_number: {{transcript_generated.call_to}}
duration: {{transcript_generated.call_duration}}
click_id: {{contact.attributionSource.gclid}}
conversion_action: [Select from dropdown]
conversion_value: 100
min_confidence: 85
min_duration: 60
→ IF/ELSE: intent = "qualified_lead"
→ Yes: Create Opportunity, Send SMS to sales team
→ No: Add tag "low-priority", Send nurture email
Form Spam Filtering
Trigger: Form Submitted
→ TrolleyShield: Analyze Form
name: {{contact.name}}
email: {{contact.email}}
phone: {{contact.phone}}
message: {{contact.message}}
form_name: "Quote Request Form"
click_id: {{contact.attributionSource.gclid}}
conversion_action: [Select from dropdown]
conversion_value: 50
→ IF/ELSE: action = "block"
→ Yes: Add tag "spam", Stop workflow
→ No: Continue to lead routing
Routing by Service Tags
If you have service tags configured, the tags output variable returns an array of matched services. You can use GHL's Array Functions (Premium) to work with this data in your workflows.
Using Array Functions with tags:
- Find — check if a specific tag exists (e.g. find
"roofing"intags) - Filter — get only tags matching a condition
- Find by Index — get the first or Nth tag
Example: Route calls by service type
Trigger: Transcript Generated
→ TrolleyShield: Analyze Call
transcript: {{transcript_generated.call_transcript}}
caller_number: {{transcript_generated.call_from}}
called_number: {{transcript_generated.call_to}}
duration: {{transcript_generated.call_duration}}
→ IF/ELSE: intent = "qualified_lead"
→ Yes:
→ Array Functions: Find "roofing" in {{tags}}
→ Found: Add to "Roofing Leads" pipeline, Notify roofing team
→ Not Found:
→ Array Functions: Find "bathroom" in {{tags}}
→ Found: Add to "Remodel Leads" pipeline
→ Not Found: Add to "General Leads" pipeline
→ No: Send nurture email
Tags are also available in Custom Code and Custom Webhooks as a standard JSON array.
You don't need Array Functions for simple workflows. You can also use tags in Custom Code actions with basic JavaScript: if (tags.includes("roofing")) { ... }
Usage & Billing
- Each call analysis counts toward your plan's call analyses limit
- Each form analysis counts toward your plan's form analyses limit
- Paid plans allow overages (billed automatically)
- Trial accounts are hard-blocked at their limits
- Synced phone numbers do not count toward your tracking number limit
Disconnecting
To disconnect GoHighLevel:
- Go to Settings → Integrations → GoHighLevel in TrolleyShield
- Click Disconnect
- GHL tracking numbers are deactivated (existing call/form data is retained)
- Optionally uninstall the app from GHL Marketplace settings
Troubleshooting
"No GHL connection found" Error
- Ensure you completed the OAuth flow from Settings → Integrations → GoHighLevel
- Check that you selected the correct GHL location during setup
- The connection may have been uninstalled from the GHL side — reconnect from TrolleyShield
"API access requires a paid plan" Error
- GHL integration requires a paid plan with API access
- Upgrade to any Call Shield plan, or Form Pro/Business
Conversion Action Dropdown Shows "TrolleyShield not connected"
- Ensure TrolleyShield is connected to the GHL location where you're building the workflow
- Check that Google Ads is connected in TrolleyShield settings
"Either transcript or recording_url is required" Error (400)
The Analyze Call action needs either a transcript or a recording URL to run. This error usually means one of the following:
- Testing the workflow without a real call — GHL only generates a transcript when an actual call is recorded and transcribed. Test runs from the workflow builder won't have a transcript value. Paste a sample transcript directly into the Transcript field temporarily, then switch back to the
{{transcript_generated.call_transcript}}variable before going live. - Call transcription isn't enabled on the number that was called. Go to Settings → Phone Numbers → Advanced Settings and enable Call Transcriptions, then enable Call Recording on each individual number.
- Wrong trigger — the Call Completed trigger doesn't expose a transcript. Use Transcript Generated instead.
- Recording URL won't work as a fallback — GHL does not expose recording URLs to workflows, so only the transcript path is available for GHL calls.
Phone Numbers Not Syncing
- Click "Sync Numbers" in Settings → Integrations → GoHighLevel
- Ensure the GHL OAuth token hasn't expired (disconnect and reconnect if needed)
- New numbers added in GHL are auto-synced when a call comes in on them