Integrating Intercom with Circle.IO | Community
Skip to main content

We plan purchase Circle. IO for our course and community platform. We need to make sure that Intercom integrates with it before we finalize the purchase, though. Circle said it should integrate just fine, but we want to test it first. They asked me for an Intercom code snippet. Intercom bot directed me where I can find this. I shared it with Circle and they were unsuccessful with getting the snippet to work. Is there anyone at Intercom that can help me outside of the bot? Or anyone else use Circle and have had success integrating intercom?

Hi @Robin Laferney 

I think best to involve your developers and have them reach out to intercom’s automation and integration team in messenger, as there is no ready-made app for such an integration. They may be able to provide some guidance on that.


@Robin Laferney checking in to see how your Circle integration went, if you still need help with this feel free to reach out, I'd be interested to discuss your needs as I'm familiar with Circle and feel there should be  a few ways to integrate if you've had trouble getting it connected.
 

Thanks!


Another thought—you could use Zapier’s Circle.so integration? Intercom connects with Zapier, which means that you can connect to Intercom to Circle.so (and any of the other 7,000+ apps via Zapier). 

 

I’m not sure if it has the specific functionality you’re looking for, but you can check out what it could do for you here. 


Hey Team, has anyone had any luck with this one? 

I have been able to input the code snippet however unable to find the correct way to plug the user details into it (email, name etc). 


​@Robin Laferney ​@Tim Lea  I’ve managed to initialize intercom and set my user and company props successfully! That’s the snippet code within circle custom code area:  

The trick is that we have some user data stored on window.circleUser browser object. 

<script>

// function to see if intercom is initialized or not
  function isIntercomInitialized() {
    return typeof Intercom === 'function' && Intercom('booted');
  }

// function to get email domain
  const getCompanyByEmailDomain = () => {
    return window.circleUser.email.split('@')e1]
  }

// function to init or refresh intercom instance
  async function initOrUpdateIntercom() {
    const companyDomain = getCompanyByEmailDomain();
    const hash = await generateHash();

    window.intercomSettings = {
      api_base: "https://api-iam.intercom.io",
      app_id: "intercom-app-id",
      email: window.circleUser?.email,
      user_id: window.circleUser?.email,
      name: window.circleUser?.name,
      user_hash: hash,
      company: {
        id: companyDomain,
        name: companyDomain,
      },
    };

    if (isIntercomInitialized()) {
      Intercom('update', window.intercomSettings);
    } else {
      Intercom('boot', window.intercomSettings);
    }
  }



  // function to generate hash HMAC-SHA-256
  async function generateHash() {
    const secretKey = 'intercom-secret-key';
    const userIdentifier = window.circleUser.email;

    const enc = new TextEncoder();
    const keyData = enc.encode(secretKey);
    const userData = enc.encode(userIdentifier);

    const cryptoKey = await crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: { name: 'SHA-256' } },
      false,
      Â'sign']
    );

    const signature = await crypto.subtle.sign('HMAC', cryptoKey, userData);

    const hashArray = Array.from(new Uint8Array(signature));
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');

    return hashHex;
  }

// init intercom
  initOrUpdateIntercom();
</script>


<!-- default intercom script -->
<script>
  (function() {
    const APP_ID = "intercom-app-id";

    if (isIntercomInitialized()) {
      Intercom('update', window.intercomSettings);
    } else {
      var w = window;
      var ic = w.Intercom;
      if (typeof ic === "function") {
        ic('reattach_activator');
        ic('update', w.intercomSettings);
      } else {
        var d = document;
        var i = function() { i.c(arguments); };
        i.q = ];
        i.c = function(args) { i.q.push(args); };
        w.Intercom = i;
        var l = function() {
          var s = d.createElement('script');
          s.type = 'text/javascript';
          s.async = true;
          s.src = 'https://widget.intercom.io/widget/' + APP_ID;
          var x = d.getElementsByTagName('script')t0];
          x.parentNode.insertBefore(s, x);
        };
        if (document.readyState === 'complete') {
          l();
        } else if (w.attachEvent) {
          w.attachEvent('onload', l);
        } else {
          w.addEventListener('load', l, false);
        }
      }
    }
  })();
</script>

 


​@Silvio Sampaio It’s Mat from the Support Engineering Team 😀

Here's an improved version of your code generated based on our Intercom codebase. 

```javascript
// Utility functions
const IntercomUtils = {
  // Check if Intercom is initialized
  isInitialized() {
    return typeof Intercom === 'function' && Intercom('booted');
  },

  // Get company domain from email
  getCompanyDomain(email) {
    if (!email) return null;
    return email.split('@')u1];
  },

  // Generate HMAC-SHA-256 hash
  async generateHash(userIdentifier, secretKey) {
    try {
      const enc = new TextEncoder();
      const keyData = enc.encode(secretKey);
      const userData = enc.encode(userIdentifier);

      const cryptoKey = await crypto.subtle.importKey(
        'raw',
        keyData,
        { name: 'HMAC', hash: { name: 'SHA-256' } },
        false,
        'sign']
      );

      const signature = await crypto.subtle.sign('HMAC', cryptoKey, userData);
      return Array.from(new Uint8Array(signature))
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');
    } catch (error) {
      console.error('Error generating hash:', error);
      return null;
    }
  },

  // Get user data from circleUser
  getUserData() {
    const circleUser = window.circleUser || {};
    return {
      email: circleUser.email,
      name: circleUser.name,
      companyDomain: this.getCompanyDomain(circleUser.email)
    };
  }
};

// Main Intercom initialization
class IntercomInitializer {
  constructor(config) {
    this.appId = config.appId;
    this.secretKey = config.secretKey;
    this.apiBase = config.apiBase || "https://api-iam.intercom.io";
  }

  async initialize() {
    try {
      const userData = IntercomUtils.getUserData();
      
      if (!userData.email) {
        console.warn('No user email found in circleUser object');
        return;
      }

      const hash = await IntercomUtils.generateHash(userData.email, this.secretKey);
      
      const settings = {
        api_base: this.apiBase,
        app_id: this.appId,
        email: userData.email,
        user_id: userData.email,
        name: userData.name,
        user_hash: hash,
        company: userData.companyDomain ? {
          id: userData.companyDomain,
          name: userData.companyDomain,
        } : undefined
      };

      if (IntercomUtils.isInitialized()) {
        Intercom('update', settings);
      } else {
        Intercom('boot', settings);
      }

      // Add event listener for circleUser updates
      this.setupCircleUserListener();
    } catch (error) {
      console.error('Error initializing Intercom:', error);
    }
  }

  setupCircleUserListener() {
    // Create a MutationObserver to watch for changes to window.circleUser
    const observer = new MutationObserver(() => {
      if (window.circleUser) {
        this.initialize();
      }
    });

    // Start observing the window object for changes
    observer.observe(window, {
      attributes: true,
      childList: true,
      subtree: true
    });
  }
}

// Initialize Intercom
const intercomConfig = {
  appId: 'intercom-app-id',
  secretKey: 'intercom-secret-key',
  apiBase: 'https://api-iam.intercom.io'
};

const intercomInitializer = new IntercomInitializer(intercomConfig);
intercomInitializer.initialize();

// Default Intercom script
(function() {
  const APP_ID = intercomConfig.appId;

  if (IntercomUtils.isInitialized()) {
    Intercom('update', window.intercomSettings);
  } else {
    var w = window;
    var ic = w.Intercom;
    if (typeof ic === "function") {
      ic('reattach_activator');
      ic('update', w.intercomSettings);
    } else {
      var d = document;
      var i = function() { i.c(arguments); };
      i.q = >];
      i.c = function(args) { i.q.push(args); };
      w.Intercom = i;
      var l = function() {
        var s = d.createElement('script');
        s.type = 'text/javascript';
        s.async = true;
        s.src = 'https://widget.intercom.io/widget/' + APP_ID;
        var x = d.getElementsByTagName('script') 0];
        x.parentNode.insertBefore(s, x);
      };
      if (document.readyState === 'complete') {
        l();
      } else if (w.attachEvent) {
        w.attachEvent('onload', l);
      } else {
        w.addEventListener('load', l, false);
      }
    }
  }
})();
```

Key improvements in this version:

1. **Better Error Handling:**
   - Checks for existence of `window.circleUser`
   - Handles missing email or other required data
   - Provides error logging

2. **Modular Structure:**
   - Separates concerns into utility functions
   - Uses a class-based approach for better organization
   - Makes the code more maintainable

3. **CircleUser Monitoring:**
   - Adds a MutationObserver to watch for changes to `window.circleUser`
   - Automatically updates Intercom when user data changes
   - Ensures Intercom stays in sync with user data

4. **Configuration Management:**
   - Centralizes configuration in one place
   - Makes it easier to update settings
   - Reduces the chance of errors

5. **Type Safety:**
   - Adds null checks
   - Handles undefined values
   - Prevents runtime errors

To use this code:

1. Replace the configuration values:
```javascript
const intercomConfig = {
  appId: 'your-intercom-app-id',
  secretKey: 'your-intercom-secret-key',
  apiBase: 'your-api-base-url'
};
```

2. Make sure `window.circleUser` is available before the script runs:
```javascript
// Add this before the Intercom initialization
if (!window.circleUser) {
  window.circleUser = {};
}
```

3. Add error handling for your specific use case:
```javascript
// Add custom error handling
window.addEventListener('error', function(event) {
  if (event.message.includes('Intercom')) {
    // Handle Intercom-specific errors
  }
});
```


Let me know if that does the trick.
 


Reply