This post was updated on January 6, 2021 to use Bitly’s API v4, which changed how to authenticate to their API.


This post is inspired by Jared Baker who asked about how to integrate Salesforce and Bitly to create short urls to include in email alerts.

This was a fun challenge and I ended up using @InvocableMethod apex class so that the URL shortening could be kicked off by Process Builder. In my example below, I added a custom field “Short URL” to the Case object. I have a single Process that kicks off when a Case is created or updated and monitors when the “Short URL” field changes. If the field is blank then it calls out to Bitly to generate the url asynchronously (the async part is important and I’ll discuss that later). When the “Short URL” field becomes non-blank then Process Builder sends an email alert to the case owner with the shortened link.

Step 1. Sign-up for Bitly (FREE)

To use the Bitly API you will need to register. You can sign-up using Twitter, Facebook, or create a new login with their service. I chose to create a Bitly specific login because I don’t like sharing my social logins with websites.

Step 2. Generate a Bitly API Access Token

Go to https://bitly.is/accesstoken to generate an access token you can use with the Bitly API.

You’ll be prompted for your Bitly password, enter it then click Generate Token. A pop-up will appear with your new access token, copy it and store it someplace secure.

bitly-generate-token

Step 3. Find Your Bitly Group ID

When using the Bitly API, instead of authenticating with your username and password you’ll instead use a Bitly group id and an access token. You generated an access token in the prior step. Now you need to find your group id. The group id is displayed in the URL when logged in to Bitly:

https://app.bitly.com/[group_id]/bitlinks/

If you have a paid account, you might consider creating a test group as described here.

Step 4. Create Named Credential in Salesforce

In Salesforce, go to Setup and enter “Named Credential” in the quick find box, then click Named Credentials. Create a new Named Credential to securely store your Bitly group id and access token.

  • Label: Bitly
  • Name: Bitly
  • URL: https://api-ssl.bitly.com
  • Identity Type: Named Principal
  • Authentication Protocol: Password Authentication
  • Username: <your bitly group id>
  • Password: <your bitly access token>
  • Allow Merge Fields in HTTP Header: ✅
  • Allow Merge Fields in HTTP Body: ✅

bitly-named-credential

Step 5. Create Custom Field “Short URL”

Create a custom URL field on your objects of interest to store the Bitly generated short urls. Depending on your situation you may have one or more. The sample code I share only supports one on the Case object, but you can easily adapt the code to your needs.

Step 6. Create Bitly Apex Classes

I developed two classes, one that encapsulates the Bitly http callouts and the other to expose the service as @InvocableMethod so it can be invoked by Process Builder or Flow Builder. An important point to note is that the BitlyShortenURLInvocable class actually calls a @Future method to generate the short urls asynchronously. This is required because if you don’t then you’ll get an error that you have uncommitted work and you must either commit or rollback before making the http callout to the Bitly service. When the async process completes then it updates the Case objects with the new short urls.

/**
* Simple service to make http callout to Bitly url shortener service.
*/
public class BitlyService {
/**
* Given a long URL will return the shortened version.
* https://dev.bitly.com/api-reference#createBitlink
*/
public String shorten(String url) {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Bitly/v4/shorten');
req.setMethod('POST');
req.setHeader('Authorization', 'Bearer {!$Credential.Password}');
req.setHeader('Accept', 'application/json');
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serialize(new Map<String, Object>{
'group_guid' => '{!$Credential.UserName}',
'long_url' => url
}));
HttpResponse res = new Http().send( req );
Map<String, Object> response = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
return (String) response.get('link');
}
}

public class BitlyShortenURLInvocable {
@InvocableMethod(
label = 'shorten'
description = 'Given case IDs then generates a bitly short url for them'
)
public static void shorten(List<ID> caseIds) {
// You can't invoke http callouts from Process Builder or Flow
// because the database transaction has not committed yet, you will get error:
// "System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out"
// To get around this then we'll actually make the call in a @Future method asynchronously.
shortenAsync( caseIds );
}
@Future(callout = true)
private static void shortenAsync(List<ID> caseIds) {
// Fetch your data and a field where you want to store the generated short url
List<Case> cases = new List<Case>([ SELECT Id, Short_URL__c FROM Case WHERE Id IN :caseIds ]);
// Service to actually call out to bitly and get a shortened url
BitlyService service = new BitlyService();
// Bitly does not support bulk url shortening
// so you must make each call individually.
// Do be aware of Bitly's rate limiting if you try
// to mass create a bunch of records in short succession
// https://dev.bitly.com/docs/getting-started/rate-limits
for ( Case caseObj : cases ) {
// in this trivial example, we're just creating short urls to the record itself
caseObj.Short_URL__c = service.shorten( 'https://login.salesforce.com/' + caseObj.id );
}
// update the records with their short urls
// use workflow or trigger to fire off the short url field being populated
// to then send email alerts, etc. including the short url
if ( cases.size() > 0 ) {
update cases;
}
}
}

Test classes are available here. For more information, check out Testing HTTP Callouts.

Step 7. Create Process to Automate URL Shortening

In our simple example, navigate to Process Builder to create a new Process on the Case object whenever it is created or edited.

  1. The first decision criteria should check if the custom “Short URL” field is blank.
    • If true then call Apex class BitlyShortenURLInvocable, passing in the case record’s ID
  2. The second decision criteria should check if the custom “Short URL” field is not blank and was changed.
    • If true then send an email alert or some other action to use the now populated “Short URL” field

bitly_process_builder

Step 8. Create a New Case!

Activate your Process then go to create a new Case. Once saved, you may need to refresh the page after a couple seconds and then you’ll notice the “Short URL” field has been populated. Voila!

bitly_case

In this example, I setup a simple email alert to the Case owner with the short url link as shown in this screen shot:

bitly_email_alert