Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Heroku Enterprise
  • Heroku Connect (Salesforce sync)
  • Heroku Connect Reference
  • Using Custom Triggers with Heroku Connect

Using Custom Triggers with Heroku Connect

English — 日本語に切り替える

Last updated November 29, 2022

Table of Contents

  • Understanding xmlbinary
  • Make Changes in Response to Data Coming from Salesforce or To Foreign Tables
  • Alter the Result of Your Own Data Change Statements

Custom triggers aren’t officially supported and Heroku Support can’t provide help with them. Proceed at your own risk.

Heroku Connect uses Postgres triggers to observe changes in your Connect tables and write your changes to Salesforce. Implementing your own custom triggers on Connect tables can create additional load and Connect can miss your updates.

Understanding xmlbinary

Heroku Connect uses a Postgres variable called xmlbinary in its own triggers. The value of xmlbinary determines whether to send updates to Salesforce. This variable is how Connect prevents sending its own updates back to Salesforce and creating an infinite loop.

Connect triggers detect row updates to send to Salesforce when the xmlbinary value is base64. Connect triggers ignore row updates when xmlbinary is hex. You can set this value in your own custom trigger to temporarily enable or disable sending updates to Salesforce.

Make Changes in Response to Data Coming from Salesforce or To Foreign Tables

When reacting to changes coming from Salesforce, use an AFTER trigger to temporarily change the value of xmlbinary to base64. Restore the previous value after you have made your changes. This method also works well if you’re altering data in another table that requires capturing.

Here’s an example for a Contact mapping:

  1. A Contact record created in Salesforce and written to your Heroku Postgres database with Connect as part of normal sync operations.
  2. A trigger updates the row in Heroku Postgres with an externalid__c.
  3. Heroku Connect detects this update and syncs it back to Salesforce.

The custom trigger for the Contact example looks like:

CREATE OR REPLACE FUNCTION salesforce.contact_external_id_proc() RETURNS TRIGGER AS $$
DECLARE
  oldxmlbinary varchar;
BEGIN
  -- Save old value
  oldxmlbinary := get_xmlbinary();

  -- Change value base64 to ensure writing to _trigger_log is enabled
  SET LOCAL xmlbinary TO 'base64';

  -- Add your custom trigger code here.

  -- Update the external ID
  UPDATE salesforce.contact SET externalid__c = gen_random_uuid()
  WHERE id = NEW.id;

  -- Your custom trigger code ends here.

  -- Reset the value
  EXECUTE 'SET LOCAL xmlbinary TO ' || oldxmlbinary;

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS contact_after_trigger ON salesforce.contact;

CREATE TRIGGER contact_after_trigger
  AFTER INSERT OR UPDATE ON salesforce.contact
  FOR EACH ROW
  WHEN (get_xmlbinary()::text = 'hex'::text AND NEW.externalid__c IS NULL)
  EXECUTE PROCEDURE salesforce.contact_external_id_proc();

Connect often INSERTs, UPDATEs, or DELETEs thousands of records at a time. Ensure that custom triggers perform well with large volume of records by testing in staging. These triggers also work best when they don’t write many changes per record change. Additionally, use simple calculations over complex calculations. Complex calculations can have an adverse impact on the speed of writing data from Salesforce.

Alter the Result of Your Own Data Change Statements

You can also use custom triggers to alter the data captured by Connect in response to your own SQL statements. For example, you can ensure that a UUID External ID is inserted every time you write a new record to your database. In this case, use a BEFORE trigger so that Connect picks up with the original INSERT statement.

Continuing with the Contact example from the previous section, the BEFORE trigger looks like this:

CREATE OR REPLACE FUNCTION salesforce.contact_external_id__before_proc() RETURNS TRIGGER AS $$

BEGIN
  -- Add your custom trigger code here.

  -- Update the external ID
  NEW.external_id__c := gen_random_uuid();

  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS contact_before_trigger ON salesforce.contact;

CREATE TRIGGER contact_before_trigger
  BEFORE INSERT OR UPDATE ON salesforce.contact
  FOR EACH ROW
  WHEN (get_xmlbinary()::text = 'base64'::text AND NEW.externalid__c IS NULL)
  EXECUTE PROCEDURE salesforce.contact_external_id_before_proc();

In this case, the WHEN condition guarantees that xmlbinary is base64. There’s no need to set or unset its value to ensure that Connect captures the change with the rest of the record.

Keep reading

  • Heroku Connect Reference

Feedback

Log in to submit feedback.

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices