Skip to main content

Support makers launching on Product Hunt

· 9 min read
Norah Sakal

Cover image

Goal: Get an email every time someone you follow on Twitter is launching anything on Product Hunt

Update February 28th, 2023

Update February 28th, 2023

Redacted values and the absence of Twitter usernames in the API response indicate that the Product Hunt API has undergone some significant changes.

The recent changes in the Product Hunt API affect this guide, and you can no longer map the Product Hunt API response with the Twitter API response.

I've written a post about the changes: RIP Product Hunt API: What it means for developers

This Tweet sparked an idea:

Tweet sparking idea

I love Product Hunt and have launched 5 different products so far, but I don't always have time to scroll through the launches every day.

But I still want to support all the makers I'm following and check out their products.

So let's build a micro service that sends you an email every morning with a summary of all the makers you are following and launching anything daily.

Here's what we'll use:

🐦 Twitter API

🚀 Product Hunt API

🐍 Basic Python

⚙️ REST API calls

Outline

1. Fetch all the tech posts launching today on Product Hunt

2. Fetch a list of all your Twitter following

3. Check if any maker is launching

4. Send an email if any maker is launching

5. Automate daily maker check with automatic cron job

1. Fetch all the tech posts launching today on Product Hunt

Before fetching the daily Product Hunt posts, you need a developer token, an API key + API secret. Visit Product Hunt, hover over your profile image in the upper right corner and click on API dashboard in the appearing menu. Product Hunt dashboard

Click on add an application, name it and save it.

Create a new application

Once you have created an application, click on create developer token below the newly created application, and now you'll have all the API credentials you need. Save the generated token for the next step where we'll make an API call.

Product Hunt API keys

Back to fetching all the tech posts launched today, this API call will give us all the maker user ids for each project. The Product Hunt API is reachable at https://api.producthunt.com/v1/<ENDPOINT>

Here's the endpoint for fetching the tech posts of today:

api_url_posts = "https://api.producthunt.com/v1/posts"

Constructing our header is simple since we're only going to access public endpoints. Public endpoints only need the client-level access token in the header:

headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + api_token_ph,
'Host': 'api.producthunt.com'
}

Your API token was created in the Product Hunt API dashboard generated earlier. Use the Python library requests to call the API endpoint.

Here's the entire snippet:

import json
import requests

api_token_ph = "PH_TOKEN"
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + api_token_ph,
'Host': 'api.producthunt.com'
}

api_url_posts = "https://api.producthunt.com/v1/posts"
response = requests.get(api_url_posts, headers=headers)

Inspecting the length of the response, today we have 33 tech posts launching:

Launching posts today

Further inspecting the keys, for this case, only a subset is of interest for our application: name, tagline, makers:

Response columns

Now that we have the information needed for each project let's create a dict with all the makers for later matching.

maker_dict = {}
for product in response.json()['posts']:
for maker in product['makers']:

if maker['twitter_username']: # Only save if maker has a Twitter handle

product_data = {
"prod_name": product['name'],
"prod_tagline": product['tagline'],
"maker_name": maker['name'],
"twitter": maker['twitter_username']
}

if maker['twitter_username'] in maker_dict:
maker_dict[maker['twitter_username']].append(product_data)
else:
maker_dict[maker['twitter_username']] = [product_data]

Since each maker potentially could launch (or hunt) multiple projects each day, we're creating a dict where each key is the maker, and each value is a list of all the products a maker is launching that day.

Let's also create a set with each Twitter handle for comparison later on:

maker_twitter_handle_set = set(maker_dict.keys())

This is everything needed for the Product Hunt part, next step is to create a similar set, but with makers you're following on Twitter.

2. Fetch a list of all people you follow on Twitter

To match your Twitter following with the makers launching on Product Hunt, we'll call an API endpoint that returns all the people you're following on Twitter.

The first step is to get a bearer token from your Twitter developer account to be able to call the Twitter API.

Go to the dashboard of your Twitter developer account, click + Add App, choose Create new, pick an environment and then choose a name. Make sure to save the bearer token revealed at the last stage, and you'll need the token when we're making calls to the API endpoints later on.

Twitter developer portal

The Twitter API is reachable at https://api.twitter.com/2/<ENDPOINT> and the endpoint that gives you a user's following is this one:

API_URL_FOLLOWING = "https://api.twitter.com/2/users/:id/following"

For this endpoint, you'll need the numerical username id for your Twitter user. You can either use another API endpoint called user lookup or search for a Twitter id and username converter online.

Here's how you do it with the API:

username = "YOUR_TWITTER_USERNAME"
twitter_bearer_token = "YOUR_BEARER_TOKEN"

search_url = f"https://api.twitter.com/2/users/by/username/{username}"
search_headers = {
'Authorization': 'Bearer {}'.format(twitter_bearer_token)
}
search_resp = requests.get(
search_url,
headers=search_headers,
params={
"user.fields":"id" # Specifically ask for the id
}
)

The response will give you the numerical user id:

Numerical Twitter user id

We can use the numerical Twitter user id to fetch your followers:

numerical_user_id = "YOUR_NUMERICAL_USER_ID"
twitter_bearer_token = "YOUR_BEARER_TOKEN"

search_url = f"https://api.twitter.com/2/users/{numerical_user_id}/following"
search_headers = {
'Authorization': 'Bearer {}'.format(twitter_bearer_token)
}
search_resp = requests.get(
search_url,
headers=search_headers,
params={
"user.fields":"username" # We only need the Twitter handle from the user fields
}
)

Notice that we only need the Twitter handle in the user fields, hence adding "user.fields":"username" to the parameters in the API call.

Since each username is unique, we can create a new set with each Twitter handle that you're following.

twitter_following_set = set([user['username'] for user in search_resp.json()['data']])

Now you have a set with everytone you're following on Twitter, ready to match with the previously created set with launching makers.

3. Check if any maker is launching

Compare the sets. You'll get a new dict with Twitter handles if the sets match.

matches = set(maker_twitter_handle_set) & set(twitter_following_set)
# eg {'twitter_handle_1','twitter_handle_2'}

4. Send an email if any maker is launching

If there is a match, let's compose an email:

email_text = ""
for maker_id in matches:
launch_text = f"The maker {maker_dict[maker_id][0]['maker_name']} @{maker_dict[maker_id][0]['twitter']} that you are following on Twitter just launched {len(maker_dict[maker_id]) + ' products' if len(maker_dict[maker_id])>1 else 'a product'} on Product Hunt 🚀 "

prod_texts = ""
for product in maker_dict[maker_id]:
prod_texts += f"Product name: {product['prod_name']}"
prod_texts += f"Product tagline: {product['prod_tagline']}"

email_text += launch_text + prod_texts

The final email will look something like this:

Email maker launching on Product Hunt

The last step is to send the email to notify you about this maker launching a new product. We're using Amazon Simple Email Service (AWS SES) for this.

What is AWS SES?

SES is a cost-effective, flexible, and scalable email service that enables you to send emails from within any application.


The code snippet needed to send the email with SES is the following:

ses_client = boto3.client('ses')

sender_email = "FROM_EMAIL_ADDRESS"
receiver_email = "TO_EMAIL_ADDRESS"
subject = "EMAIL_SUBJECT"

email_confirmation = ses_client.send_email(
Destination={
'BccAddresses': [],
'CcAddresses': [],
'ToAddresses': [receiver_email],
},
Message={
'Body': {
'Html': {
'Charset': 'UTF-8',
'Data': email_text,
},
'Text': {
'Charset': 'UTF-8',
'Data': email_text,
},
},
'Subject': {
'Charset': 'UTF-8',
'Data': subject,
},
},
ReplyToAddresses=[],
Source=sender_email,
)

5. Automate all the code with an automatic cron job every morning

Unless you want to do this manually every day, let's create an automation that will run all these steps daily.

I'd like to receive this email every morning at 7 am, so I can read it while drinking my first cup of coffee. To automate this, we'll use a recurring cron job that runs every morning.

What is a cron job?

A cron job is a command used for scheduling tasks to be executed sometime in the future and is normally used to schedule a job that is executed periodically. Like in this case, when we want to check for launching makers daily.


I'm in PST and 7 am means 2 pm in UTC. Since the cron jobs in AWS are in UTC, we need to consider when to schedule the task. Cron uses 24 hour format, hence 14 for 2 pm.

Here is what a cron job configuration looks like for 2 pm UTC:

Cron job configuration

Summary

1. Get all the tech posts of today on Product Hunt

2. Create a set of all the makers

3. Get all your following on Twitter

4. Create a set with all your following

5. Match the list of launching makers with the list of following

6. Write an email if any of your following are launching anything today

7. Send the email every morning with a cron job

Next steps

1. Repo with source code

Here is the repo with a Jupyter notebook with all the source code if you'd like to implement this on your own ⬇️
https://github.com/norahsakal/support-makers-launching-product-hunt