Connection Builder
You can build your own integration from scratch using various liquid macros.
Overview
The Custom Connection Builder lets you send custom POST requests to third-party services whenever selected in-app events occur. With it, you can recreate Apphud’s built-in integrations or design your own payloads for any supported event.
Note
Connection Builder is available on Expert and Enterprise plans.

How to Add a Custom Connection
Step 1 – Create a Connection
In Apphud, navigate to Connections > Integrations, find Connection Builder at the top of the list, and click Add Connection.
As with other integrations, each custom connection is created for a specific data source platform. During setup, you’ll be prompted to select a Source:
iOS, Android, Flows, iOS (Web-to-App), or Android (Web-to-App).

Step 2 – Configure Name and URL
After selecting a source, you’ll be taken to the connection settings page. Enter a Name and URL for the connection. Events will be sent to the specified URL via POST requests.

Step 3 – Add Headers
Define request headers by specifying Header Name and Value.
To include multiple headers, click Add Header and fill in the additional fields.
Step 4 – Set Up Request Body
In the Body Configuration section, compose your JSON payload using supported Liquid macros (see macro reference below).
Step 5 – Select Events
Choose the events you'd like to send through the connection. You can also rename these events using custom labels.

Step 6 – Apply Event Filters (Optional)
Click + Where to add filters that determine when events should be sent.
If an event is enabled but doesn't match the filter conditions, it will appear as Skipped in the event logs with the reason “Event did not match filters.”

Important Note
No need to create a filter "Environment = Production". By default Apphud skips sandbox events so this filter is redundant.
Add powerful event filters to ensure only specific data is sent to a destination. For example:
- Revenue > $29
- Product duration = Weekly
- Trial started = true
These filters can be applied per connection for precise control.
Below is a list of available filters grouped by category:
General
Environment: Sandbox, Production
App Version: supports =, >, < (e.g., > 1.20.1)
User
Country by IP
Store Country
Has Advertising ID (IDFA)
Product
Type: Auto-renewable, Non-renewing
Duration: Weekly, Monthly, Annually
Family Shared
Product ID
Revenue (USD): supports comparison (<, >, =)
Attribution
Ad Network
Channel
Campaign Name
User Properties
Keys with exact values
Note
Filters do not apply to non-receipt events like user_created, paywall_shown, except for Store Country and Environment.
Step 7
Save the Connection.
The connection can be Enabled right away, however, we recommend testing a connection before enabling it.
Liquid Macros List
App
Macro | Description | Format | Example |
---|---|---|---|
{{ app.app_version }} | App Version | String | 1.2.20 |
{{ app.bundle_id }} | iOS Bundle ID | String | com.bundle.id |
{{ app.package_name }} | Android Package Name | String | com.android.package |
Event
Macro | Description | Format | Example |
---|---|---|---|
{{ event.created_at }} | Event creation date (ISO) | Date | 2022-03-12T09:38:38.081Z |
{{ event.created_at_ts }} | Event creation date (Unix seconds) | Integer | 1743481200 |
{{ event.name }} | Event name | String | custom_trial_started |
{{ event.original_name }} | Unmodified original name | String | trial_started |
{{ event.receipt.product_id }} | Product ID | String | my.weekly.id |
{{ event.receipt.purchased_at }} | Transaction date (ISO) | Date | 2022-03-12T09:38:38.081Z |
{{ event.receipt.purchased_at_ts }} | Transaction date (Unix seconds) | Integer | 1743481200 |
{{ event.receipt.intro_period }} | Introductory period (true/false) | Boolean | TRUE |
{{ event.receipt.trial_period }} | Trial period (true/false) | Boolean | FALSE |
{{ event.receipt.transaction_id }} | Transaction ID | String | 1000000999999999 |
{{ event.receipt.original_transaction_id }} | Original Transaction ID | String | 1000000888888888 |
{{ event.receipt.price_usd }} | Price in USD | Float | 9.99 |
{{ event.receipt.proceeds_usd }} | Proceeds in USD | Float | 6.99 |
{{ event.receipt.price }} | Price in local currency | Float | 199.00 |
{{ event.receipt.proceeds }} | Proceeds in local currency | Float | 139.00 |
{{ event.receipt.currency }} | Local currency ISO code | String | USD |
User
Macro | Description | Format | Example |
---|---|---|---|
{{ user.user_id }} | User ID | String | abc123xyz |
{{ user.paying }} | Is currently paying or not | Boolean | TRUE |
{{ user.payments_count }} | Payments count | Integer | 4 |
{{ user.total_spent }} | Total spent in USD | Float | 23.49 |
{{ user.idfv }} | Device IDFV | String | 12345-12345-12345 |
{{ user.idfa }} | Device IDFA | String | ABCDEF12-3456-7890-ABCD-EF1234567890 |
{{ user.properties.your_key }} | User Properties | String | myuserpropertyvalue |
{{ user.created_at }} | User Created Date (ISO) | Date | 2022-03-12T09:38:38.081Z |
{{ user.created_at_ts }} | User Created Date (Unix seconds) | Integer | 1743481200 |
{{ user.first_seen_at }} | First seen Date (ISO) | Date | 2022-03-12T09:38:38.081Z |
{{ user.first_seen_at_ts }} | First seen Date (Unix seconds) | Integer | 1743481200 |
{{ user.country_by_ip }} | Country ISO code by IP address | String | US |
{{ user.country_by_store }} | Country ISO code from the store | String | US |
{{ user.time_zone }} | Time zone | String | Asia/Jakarta |
{{ user.language }} | Language | String | en |
{{ user.ip_address }} | IP address | String | 192.168.1.1 |
{{ user.os_version }} | OS version | String | 18.2.1 |
{{ user.push_token }} | Push token | String | ABCD1234TOKEN5678 |
User LTV Predictions (Coming Soon)
Macro | Description | Format | Example |
---|---|---|---|
{{ user.pltv_30d }} | 30-day Predicted LTV | Float | 34.00 |
{{ user.pltv_90d }} | 90-day Predicted LTV | Float | 40.54 |
{{ user.pltv_365d }} | 365-day Predicted LTV | Float | 42.55 |
Attribution
Macro | Description | Format | Example |
---|---|---|---|
{{ user.attribution.appsflyer_id }} | AppsFlyer ID | String | AF_ID_123456 |
{{ user.attribution.fb_anon_id }} | Facebook Anon ID | String | FBANONID123 |
{{ user.attribution.fb_ext_info }} | Facebook Ext Info | String | EXTINFO_SAMPLE |
{{ user.attribution.firebase_id }} | Firebase ID | String | firebase-user-id |
{{ user.attribution.adjust_id }} | Adjust ID | String | adjust-uuid-xyz |
{{ user.attribution.provider }} | Attribution provider | String | Apple Search Ads Integration |
{{ user.attribution.ad_network }} | Ad Network | String | Meta Ads |
{{ user.attribution.channel }} | Channel | String | |
{{ user.attribution.campaign }} | Campaign | String | my-us-campaign |
{{ user.attribution.fbc }} | FBC | String | fb.1.1234567890.111 |
{{ user.attribution.fbp }} | FBP | String | fb.1.1234567890.222 |
Click Event
Macro | Description | Format | Example |
---|---|---|---|
{{ user.attribution.ttclid }} | TikTok Click ID | String | tiktok-click-id-xyz |
{{ user.attribution.gclid }} | Google Click ID | String | GOOGLE123CLICK |
{{ user.click_event.properties.custom_param }} | Click event custom param | String | value |
Macro | Description | Format | Example |
---|---|---|---|
{{ user.click_event.properties.click_id }} | Click ID | String | click1234 |
{{ user.click_event.user_agent }} | User Agent from click event | String | Mozilla... |
{{ user.click_event.properties.utm_campaign }} | UTM Campaign | String | spring_sale |
{{ user.flow_properties.any_custom_param }} | Flow custom param | String | value2 |
Special Functions
You can also check the "Remove null values" setting under the "Request body" field to ensure such parameters won't be sent.
Conditional Logic in JSON
With Connection Builder, you can embed conditional logic directly in your request body using Liquid if/else
tags.
Example: Send a has_idfa
flag based on the availability of IDFA:
"has_idfa": {% if user.idfa %} 1 {% else %} 0 {% endif %}
You can also apply conditions to multi-line blocks or entire JSON payloads:
{% if user.country == "US" %}
{ "region": "NA" }
{% else %}
{ "region": "Other" }
{% endif %}
Value Modifiers
Transform values on the fly using built-in modifiers. Examples include arithmetic operations, string formatting, and date formatting.
Arithmetic:
"revenue_x2": {{ event.receipt.price | times: 2 }}
String case formatting:
"product": "{{ event.receipt.product_id | upcase }}"
Date formatting:
For more on date formatting, check this Liquid guide.
"event_time": "{{ event.created_at | date: "%Y-%m-%d %H:%M:%S.000" }}"
UNIX timestamp:
"timestamp": "{{ event.created_at | date: "%s" }}"
For more on date formatting, check this Liquid guide.
Preview a Payload
While setting up your integration, you can preview the generated payload at any time. Click the eye 👁️ icon in the JSON editor toolbar, then enter an Event ID or Transaction ID to view the payload.
- Event ID. It's the Apphud's internal event ID which can be found in the Events tab. Include ID column in the table. If the ID column doesn't exist, try to clear browser cache first.
- Transaction ID. Store's Transaction ID.
Note: This preview does not trigger an actual HTTP request.

Test a Connection

To simulate a real connection, enter a valid Transaction ID from your app. Apphud will fetch the corresponding event, receipt, and user data, then send a test POST request using your configuration.
All configured filters will be applied during the test.
Note: If you're using a sandbox transaction, be sure to include the filter
Environment = Sandbox
. Otherwise, the event will be skipped.
- If the transaction is invalid or belongs to a different app, an error message will appear: "Transaction was not found."
- If the test is successful, a popup will display the response payload.
⚠️ Keep in mind: the test result is shown only once and cannot be accessed again after closing the popup.
Updated 1 day ago