You can try the private API out for yourself using
threads-api
. View the documentation to get started.
As soon as Instagram released their Twitter replacement on July 5, 2023, I got started on trying to figure out how I can make a post to Threads from my own server.
At first, I noticed that although going to threads.net simply presented a QR code to download the app, manually navigating to threads.net/{username}
loaded the user’s profile. You can’t interact with it, but at least I can use my handy-dandy DevTools to inspect the requests Threads is making to query the profile information.
I found that they simply make a POST
request to https://www.instagram.com/api/graphql with some special headers and a URL encoded body including the userID
(keep in mind that since Threads shares accounts with Instagram, the userID
s are actually Instagram’s). The request includes my ID (1966227960
), but I can replace that ID to load another user’s basic Threads profile information (like bio, profile picture, etc.).
This is cool and all, but since the web app doesn’t support publishing threads (or even logging in), it doesn’t help me in my mission to make a post from my own server.
This is where the real reverse engineering comes into play 😈
We already know that you can download the Threads iOS/Android app, and make a post from there. All that app is doing is making a request to Threads’s server, which is replicable as long as you know what’s in the request (and where it’s going). All we’d need to do is intercept that request (inspect its contents) and then we’d know exactly how to publish posts using their private API!
Although I initially went down many different rabbit holes (Objection, Frida, etc.) to accomplish the above (since Threads, like Instagram, uses SSL pinning), someone else swooped in with a pre-rooted APK of the Threads app.
Let’s pause for a second so I can explain what I’m talking about. To actually see requests made by a mobile app, we need to connect to something that acts as a middleman between the mobile app and where it’s making the request. That way, we can read the request’s contents while still allowing the request to go through. This is called a proxy, and it allows us to intercept SSL requests from connected devices. The proxy I used is called Proxyman.
Now, as I mentioned above, Threads uses a technique called SSL pinning, which basically protects against using a proxy. When I connected my iPhone to the proxy and launched the Threads iOS app, the requests would get rejected. To defeat the SSL pinning, we need to make changes to the app’s code (patch it). This is where Android’s APKs come in.
It’s easier to patch Android’s APKs then iOS’s IPAs, and we can run an Android APK from an emulator in Android Studio. This lets us do all the reverse engineering on one device.
Since Eltion already graciously patched the Threads APK for us, all we need to do is:
.apk
onto the emulator)All I had to do is create a new post from the emulator and take note of how the request was made to Thread’s (which is really Instagram’s) server.
I contributed the publishing code to junhoyeo’s threads-api repo. You can view the code and use it for yourself there!