← Back to blog

Firebase Extensions – Shorten URLs

Gonçalo Palma

Lead Flutter Developer

1st August, 2023

Need a custom tool? Invertase can help

Tired of investing in off-the-shelf software that doesn't quite fit your business? Invertase can build solutions tailored to your exact needs. Tell us what you're looking for here and we'll be in touch.

Sharing is one of the most common features in modern web and mobile applications. It allows us to show a social media post or a photograph we took to a friend, share the planning for an upcoming business travel with our company, or even send that item from an e-commerce website to Santa to have a PS5 finally. To do so, we copy the URL for that specific website (or use the Share function on our devices), and we send it via different outlets – social media, messaging apps, snail mail, or others so that other people can click on it and see what we wanted to share.

The problem with overcomplicated URLs

If we look at the URLs we share, we see that, as with many things, they come in different shapes and formats. They can be just a URL that links to the homepage of a blog:

https://gpalma.pt

Or they can have different paths and query parameters that make the URL very long and, sometimes, illegible at first look:

https://www.google.pt/search?q=gpalma&sxsrf=APwXEdeCQLFcPi9AX3B4e38Zac8DeUlMdw%3A1684584069756&source=hp&ei=hbZoZKLfK7ubkdUPrJ-L4As&iflsig=AOEireoAAAAAZGjElUPo1owxQ_FzOHwvfXscfUZPgnz9&ved=0ahUKEwjitcfY7IP_AhW7TaQEHazPArwQ4dUDCAk&uact=5&oq=gpalma&gs_lcp=Cgdnd3Mtd2l6EAMyBwguEIAEEAoyBwgAEIAEEAoyBwgAEIAEEAoyBwgAEIAEEAoyBwgAEIAEEAoyBwgAEIAEEAoyBwgAEIAEEAoyCgguEIAEENQCEAoyBwgAEIAEEAoyBwguEIAEEAo6BwgjEIoFECc6BQgAEIAEOgsILhCABBDHARDRAzoKCC4Q1AIQgAQQCjoNCC4QgAQQxwEQrwEQClAAWIAEYOwIaABwAHgAgAGuAYgB4gaSAQMwLjaYAQCgAQE&sclient=gws-wiz

Let’s share this second link via social media or messaging. In that case, It will make the message/post very long, with the chance of the person missing the first few sentences we shared before pasting the URL, or worse, it goes beyond the character limit of the platform we are using.

Let’s look at it from another perspective – what if we store URLs in our application’s database? Maybe we are generating a URL for a user’s shopping cart that makes heavy use of different path and query parameters to specify the current state of the operation:

https://my-amazing-shopping-app.com/shop/cart?id=b80b3d15-ae4f-456b-89ce-126fd352dbd9&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&theme=dark&date=1684574524886&ref=megabananaz003

As per our app architecture, we update the user’s object on our database with this URL each time a new cart operation is performed. This example URL has 296 bytes, which means that if we have 10.000 users, we will have 2,96 MB of data in this field. What if we also allow our users to save a list of external websites in their preferences? In that case, we are still determining how many characters we will have per entry, meaning we can’t even calculate the total amount of data and potentially the cost of storing that data.

Reducing our URL size with bit.ly

In both cases, either sharing externally or storing in our app’s database, we could make our life’s easier by sanitizing and shortening the URLs we use. This means that instead of using the original URL, which has an undetermined number of characters, we would build a URL with a prefix and a short code that would redirect to the original URL, such as gp.com/XYZ123, with gp.com being the prefix and XYZ123 the unique code that points to a specific URL.

Fortunately, services like bit.ly do this for us automatically, where the previously shared URL that was stored in the database is shortened to https://bit.ly/3IrEbFA, meaning that in our database, it would change the total byte size from 296 to 22, reducing it by 93%, and the number of characters to 22, making it much easier to share in any application.

To create our bit.ly shortened URLs, we must go to the website, sign up, and click the “Create New” button on the left navigation drawer.

Then, we can customize our link as needed by providing the URL and a back-half to make the link more personal, and if we upgrade to premium, we can add a custom domain instead of bit.ly.

The previous example creates the URL bit.ly/gpalma that redirects to https://a-really-long-url.io/with-path?and=queryParameters. Moreover, if we check our URL in the dashboard, we can see different Analytics, such as the number of clicks, the location, and where it was clicked.

If we want to implement this feature in our application, we could head straight to bit.ly’s developer documentation and see how to make it work. However, if we are using Firebase, there’s an easier way to achieve it – via Firebase Extensions, which allows us to quickly add features to our Firebase application directly from an Extensions Hub, in the same way, that we would add a pub.dev library to our Flutter project. Let’s see how we can make it work in an existing Firebase project.

The project – Wall of Sharing

The “Wall Of Sharing” app allows users to share their work by creating a new post composed of a title and a URL.

As a starting point to add the extension, we can use this Zapp.run project with the Wall of Sharing Flutter project:

We need to change the firebase_options.dart file to use our Firebase project’s configuration, and we can run and test our Firebase Extensions.

Firebase Firestore is used to save this data in a collection called posts, and when creating a new entry, we only send the title and url parameters using the following Dart function:

  Future<void> _createPost(String title, String url) async {
    await FirebaseFirestore.instance.collection('posts').add({
      'title': title,
      'url': url,
    });
  }

What we would want, ideally, is that when the data reaches Firebase, a new property called shortUrl would be created in this document with the [bit.ly] URL. To create this, we would have to create and manage a new Firebase Cloud Function with a specific Firestore Trigger using the bit.ly API to retrieve a new shortened URL to update the document with the new property. However, this would mean adding another codebase to our existing project that we would need to maintain, test and manage. Thankfully, the Firestore Shorten URLs function, created by the Firebase team, does precisely that for us.

Adding the bit.ly Firebase Extension to our project

If we navigate to the Firestore section of our project, we see a new tab at the top (with a NEW badge on the right) with the title “Extensions”.

Clicking on it displays a page with a brief explanation of Firebase Extensions and a collection of the most used ones.

We want to click “Explore Extensions Marketplace”, which would be the same as navigating to extensions.dev, where we can search for our URL-shortening Extension.

The details page of the Extension page has all the information we need to get started, including:

  • How the extension works and its pre-requisites;
  • How to add the extension to our project;
  • Costs associated with this function.

From the Getting Started section, we already have a checklist of items we need to tick before implementing this extension in our project:

  • Update our billing to Blaze instead of the free tier;
  • Enable Cloud Functions in our project;
  • Have Cloud Firestore enabled with a specific collection of documents that we want to retrieve URLs from;
  • Create a bit.ly account and generate a new API token.

For the last requirement, once the account is created for bit.ly, we can navigate to the settings page and click on Developer Settings > API to generate a new Access Token.

We can return to the Extension’s detail page, where we can check the Configurable Parameters section where we see what we can customize in this extension:

Here we can see that we need to specify the access token, created in the previous step, and the Firestore collection and sets of fields that are going to be manipulated, which in our case is going to be:

  • Collection path: posts;
  • Original Field Name: url;
  • Shortened URL Field Name: shortUrl.

To install this Extension, we can click on the “Install in Firebase Console” button, which will first show us the homepage of all of our Firebase Projects, where we can specify to which project we want to add the extension.

After selecting our project, we are presented with the Firebase Extension installation page, where we are first prompted to set up the billing to upgrade our project to Blaze if we haven’t done that beforehand.

Then, we can review the resources that will be created, in this case, a Cloud Function called fsurlshortner and a Cloud Secret Manager secret for our bit.ly access token.

Next, we review the list of all the Google Cloud Services that must be enabled in our project, as stipulated in the Extension’s description page.

Since our project needs to manipulate Firestore data and manage Secrets, we must review and provide any necessary permission.

Finally, we can configure our Extension with the parameters we’ve discussed: the access token, collection’s path, original URL field name and the field name where the extension will store the shortened URL. Since it’s all done inside a Cloud function, we must also specify its location.

As soon as we click on “Install extension”, we see a page listing all the installed extensions and where see the estimated time needed to install this new Extension.

After the necessary time to install it, we get the green light, and we can start using it in our application.

To test it, we need to create a new post and see if the shortUrl parameter is present in the document.

As expected, the document is updated with the new parameter after a brief moment, which we can then display in our application. However, we want to keep the legacy posts, without the shortened URL, and the posts with a shortened URL. For that to happen, we need to conditionally show the shortened URL, if available, and navigate to the specified web page:

TextSpan(
  text: snapshot.data![index].shortUrl ??
      snapshot.data![index].url,
  mouseCursor: SystemMouseCursors.click,
  recognizer: TapGestureRecognizer()
    ..onTap = () => launchUrl(
          Uri.parse(
            snapshot.data![index].shortUrl ??
      snapshot.data![index].url,
          ),
        ),
),

This effectively displays both posts in our Wall of Sharing:

Conclusion

We want to shorten URLs in our apps for multiple reasons. We may want it to be easier for users to share in different social media apps or to keep the SMS message we send short so we don’t have to pay extra. Whatever the reason, bit.ly not only makes it easy to reduce our URLs but also provides us with some analytics tools that can give us invaluable insights into our app.

And as we saw, this feature can be quickly embedded into our project using a Firebase Extension – we need to tinker with some initial configurations, and the Extension will reduce the URLs we provide to it via Firestore. This effectively shortens the development time of this feature to minutes instead of days of setting up Cloud Functions and tinkering with bit.ly’s API.

This example serves as a perfect showcase of the power and ease of use of Firebase Extensions. Stay tuned to learn about more Extensions in the future!

Stay tuned for more updates and exciting news that we will share in the future. Follow us on Invertase TwitterLinkedin, and Youtube, and subscribe to our monthly newsletter to stay up-to-date. You may also join our Discord to have an instant conversation with us.

Gonçalo Palma

Lead Flutter Developer

Categories

Tags