Posting Untappd Checkins to Mastodon (and other services)


I'm a big fan of Untappd. It's a social drinking app which lets you check in to a beer and rate it. Look, we all need hobbies, mine is drinking cider. You can see a list of everything I've drunk over the 13 last years. Nearly 900 different pints!

After checking in, the app automatically posts to Twitter. But who wants to prop up Alan's failing empire? Not me! So here's some quick code to liberate your data and post it elsewhere.

There are two ways - APIs and Screen Scraping.

API

First up, a big disclaimer. Untappd had an API - but aren't accepting new users:

Thank you for your interest in Untappd’s API. At this time, we are no longer accepting new applications for API access as we work to improve our review and support processes. We do not have a planned date to begin accepting new applications, so please check back soon.

If you already have an API key (and I do) you can call your own data. This code saves the ID of the most recent checkin to a file. Each time it runs, it checks in the ID in the file is the same as what's returned by the API. If they are different, the post is published and the new ID is saved.

This is rough and ready code:

Python 3 Python 3#!/usr/bin/env python
from mastodon import Mastodon
import json
import requests
import config

#  Set up access
mastodon = Mastodon( api_base_url=config.instance, access_token=config.write_access_token )

#   Untappd API - grab the most recent checkin
untappd_api_url = 'https://api.untappd.com/v4/user/checkins/edent?limit=1&client_id=' + config.untappd_client_id + '&client_secret='+ config.untappd_client_secret

r = requests.get(untappd_api_url)

untappd_data = r.json()

#   Latest checkin object
checkin = untappd_data["response"]["checkins"]["items"][0]
untappd_id = checkin["checkin_id"]

#   Was this ID the last one we saw?
check_file = open("untappd_last", "r")
last_id = int( check_file.read() )
print("Found " + str(last_id) )
check_file.close()

if (last_id != untappd_id ) :
    print("Found new checkin")
    check_file = open("untappd_last", "w")
    check_file.write( str(untappd_id) )
    check_file.close()
    #   Start creating the message
    message = ""

    if "checkin_comment" in checkin :
        message += checkin["checkin_comment"]

    if "beer" in checkin :
        message += "\nDrinking: " + checkin["beer"]["beer_name"]

    if "brewery" in checkin :
        message += "\nBy: "       + checkin["brewery"]["brewery_name"]

    if "venue" in checkin :
        if "venue_name" in checkin["venue"] :
            message += "\nAt: "       + checkin["venue"]["venue_name"]
    #   Scores etc
    untappd_checkin_url = "https://untappd.com/user/edent/checkin/" + str(untappd_id)
    untappd_rating      = checkin["rating_score"]
    untappd_score       = "🍺" * int(untappd_rating)

    message += "\n" +  untappd_score + "\n" + untappd_checkin_url + "\n" + "#untappd"
    print( message )
    #   Post to Mastodon. Use idempotency just in case something went wrong
    mastodon.status_post(status = message, idempotency_key = str(untappd_id))
else :
    print("No new checkin")

This doesn't do media or badges, but it's good enough to start with.

Screen Scraping

The Untappd HTML is pretty uniform, so using something like Beautiful Soup is possible.

HTML source code of the page.

Here's some code to get you started

Python 3 Python 3from bs4 import BeautifulSoup
import requests

#   Set the URL and headers
url = "https://untappd.com/user/edent"
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0'}

#   Get the HTML
response = requests.get(url)
page_html = response.text

#   Parse the HTML into soup
soup = BeautifulSoup(page_html, 'html.parser')

#   Grab the data from the first checkin

untappd_id = int( soup.find("div", class_="item")["data-checkin-id"] )

comment = soup.find("p", class_="comment-text").text

#   Steal the beer from the icon's alt text
beer = soup.find("a", class_="label").find("img")["alt"]

#   Rating is a data element
rating = soup.find("div", class_="caps")["data-rating"]

#   Was this ID the last one we saw?
check_file = open("untappd_last", "r")
last_id = int( check_file.read() )
check_file.close()

if (last_id != untappd_id ) :
    check_file = open("untappd_last", "w")
    check_file.write( str(untappd_id) )
    check_file.close()
    message = .....

And from there you should have enough to start posting your checkins everywhere. Stick that code in a crontab and have it run periodically.

Cheers!


Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

2 thoughts on “Posting Untappd Checkins to Mastodon (and other services)”

  1. said on hachyderm.io:

    @Edent Nice post. I wish i'd got access to the API before they shut it down.

    I use Cloudflare Workers to scape the page (https://www.mikestreety.co.uk/blog/turn-any-page-into-a-json-api-with-cloudflare-workers/) and turn any check-in into a JSON API (e.g. https://untappd.alehouse.rocks/user/mikestreety/checkin/1251570687)

    This then gets parsed and committed into a repo and a site built with 11ty so I can own my own reviews 🙂 https://alehouse.rocks/ Turn any page into a JSON API with Cloudflare Workers

    Reply | Reply to original comment on hachyderm.io
  2. says:

    Untappd provides a RSS feed for your checkins. The only downside is that it doesn't contain structured data, just a text summary of the checkin and any image you've added.

    You can find this URL here: https://untappd.com/account/settings

    It could be good enough for posting to mastodon without having to scrape HTML.

    Reply

What links here from around this blog?

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">