- language:python - product:chat - product:messaging ## Overview SMS Marketing is one of the most effective ways to reach consumers in a format they prefer, but every character counts when it comes to messaging. A common solution is to use a public URL shortener like bit.ly, cutt.ly, or tiny.cc. The problem with these public URL shorteners is that the carriers typically flag messages containing their URLs as spam since it is disallowed content! This application shows how **easy** it is to set up your own private URL shortener allowing you to generate and redirect shortened URLs, keep track of their usage, and most importantly you will be following all of the [carrier rules regarding shortened URLs](/guides/sms-best-practices-how-to-ensure-message-delivery#shortened-urls)! ## What do I need to run this code? View on Github [here](https://github.com/signalwire/guides/tree/main/Messaging/Private-URL-Shortener-Python)! This application doesnt require much - you will need [Python](https://www.python.org/), the [Flask framework](https://www.tutorialspoint.com/python_web_development_libraries/python_web_development_libraries_flask_framework.htm), and a [ngrok tunnel](/guides/how-to-test-webhooks-with-ngrok) to reach your localhost or server to host it on. ## How to Run Application To run the application, execute export FLASK_APP=main.py then run flask run. You may need to use an SSH tunnel for testing this code – we recommend [ngrok](https://ngrok.com/). After starting the tunnel, you can use the URL you receive from ngrok in your webhook configuration for your phone number. ## Step by Step Code Content This code repo has the following structure Static -> This folder contains the style.css and SW logo Templates -> This folder contains the shortUrls.html file .env -> This will contain your hostname variable. shortUrls.csv -> This is where the shortened URLs and data about their usage will live. This does not need to be edited - generating/deleting shortened URLs will happen on browser and their usage will update automatically on redirect to the original URL. ### Setting up .env We only need one environment variable - you will need your hostname to generate the URLs! SIGNALWIRE_HOST_NAME=https://{YourHostName}/ ### Step by step through main.py This application requires very little setup in order to handle all of your shortened URL needs for messaging. It can easily but customized in several spots which we will walk through step by step below. There are two functions - one to generate shortened URLs and one to delete shortened URLs. We will also have two Flask routes - one that redirects shortened URLs to the full URL and one that handles the shortened URL interface. The finished product will look like this: The first function we will define will handle the generation of new short URLs from full URLs. The first step is to use pandas to read in the shortUrls.csv and assign the current numbers of rows as the object_id. This number will serve to encode our full URL using Pythons [short_url](https://pypi.org/project/short_url/) implementation. We will then save some helpful data about this short URL to our dataframe and resave it to CSV. python # generate shortened URL using encoding and store in CSV def generateShortenedURL(fullURL, keyword): # read in csv using pandas shortenedUrls = pd.read_csv(shortUrls.csv) object_id = len(shortenedUrls) shortened_url = f{hostName}{keyword}/{short_url.encode_url(object_id, min_length=3)} shortenedUrls.loc[len(shortenedUrls.index)] = [fullURL, shortened_url, datetime.date.today(), Not Used Yet, 0] shortenedUrls.to_csv(shortUrls.csv, index=None) return shortened_url The next function will serve to delete the shortened URL/full URL pair from the CSV. This one is super simple - we will read the CSV into a dataframe and locate the row with the matching full URL. When we find it, we will drop it from the dataframe and resave to CSV. python # delete shortened URL from CSV def deleteShortenedURL(fullURL): # read in csv using pandas shortenedUrls = pd.read_csv(shortUrls.csv) # delete row with matching fullURL shortenedUrls.drop(shortenedUrls[shortenedUrls[Full URL] == fullURL].index, inplace=True) shortenedUrls.to_csv(shortUrls.csv, index=None) return shortened URL deleted Next, we need a route that will look up the shortened URL and redirect to the full URL. By evaluating the characters at the end of the route, we will get the decoded object ID that was used to create the shortened URL. We will again read the CSV into a dataframe and set the fullURL to the URL at the index of the decoded_id. We will also update the Last Clicked and Times Clicked columns for this row to reflect that the URL was used. We will resave the dataframe to CSV and redirect to the full URL. python # handle inbound shortened url requests and redirect to full URL @app.route(/