Skip to content

Instantly share code, notes, and snippets.

@khskekec
Last active November 5, 2025 10:58
Show Gist options
  • Select an option

  • Save khskekec/6c13ba01b10d3018d816706a32ae8ab2 to your computer and use it in GitHub Desktop.

Select an option

Save khskekec/6c13ba01b10d3018d816706a32ae8ab2 to your computer and use it in GitHub Desktop.
HTTP dump of Libre Link Up used in combination with FreeStyle Libre 3
@MrAda
Copy link

MrAda commented Sep 14, 2025

I would like to know if anyone has been able to download the "csv" file programmatically?

I looked at this but the problem is that the api call (an export post request) requires a captcha response - in other words you have to solve the captcha before you can request the csv.

I get this but maybe I can intercept this in my app and then pass the "proof" back to libreview?

@knolleary
Copy link

I have been using this successfully for some time now, although I've had to set the version header to 4.10.0 to work. I've received notifications from the LibreLink app that as of October 8th, version 4.15 and below will no longer receive data. I've tried updating the version header to 4.16.0 , but then get the 'missing header' error. Does anyone know what the latest working headers are?

@MrAda
Copy link

MrAda commented Oct 3, 2025

@knolleary I just checked the app I created and I am still using 4.7 version with no issue. I am on Android so I don't know if that matters.

@SteveCEvans
Copy link

Up until today I'd been using version 4.7, but now see the same issue as reported above:

{"data":{"minimumVersion":"4.16.0"},"status":920}

If I set the version to 4.16, I get:

{"message":"RequiredHeaderMissing"}

This is in the -eu2 region.

@knolleary
Copy link

@SteveCEvans likewise. As per my previous message, I have been receiving in-app warnings to upgrade client version before the 8th October... ie today. And sure enough, access to the API has stopped working today.

Hopefully someone can figure out the necessary headers to keep this working

@SteveCEvans
Copy link

Fixed it! I'm using micro python.

Prior to 4.16 my header for fetching graph data was:

        auth_header = {
            'Accept'        : 'application/json',
            'Authorization' : 'Bearer ' + self._user_token,
       }

And now I have:

        auth_header = {
            'Accept'        : 'application/json',
            'Authorization' : 'Bearer ' + self._user_token,
            'Account-Id'    : self._account_id
        }

Where:

            digest = uhashlib.sha256(self._user_id.encode('utf-8')).digest()
            self._account_id = ubinascii.hexlify(digest).decode('utf-8')

I hope that makes sense.

@knolleary
Copy link

@SteveCEvans well done - can confirm that works for me (intrigued to know how you figured that out...)

For reference, in node.js land, this translates to:

const { createHash } = require('crypto');
const AccountIdHeader = createHash('sha256').update(userId).digest('hex');

userId can be obtained from the response of the initial login HTTP request.

@sgmoore
Copy link

sgmoore commented Oct 9, 2025

(intrigued to know how you figured that out...)

Perhaps by reading this gist? This change has been rolling out slowly since last year - See https://gist.github.com/khskekec/6c13ba01b10d3018d816706a32ae8ab2?permalink_comment_id=5330300#gistcomment-5330300

@knolleary
Copy link

@sgmoore ha - good point. So many replies and collapsed comments, I had missed that.

@SteveCEvans
Copy link

@SteveCEvans well done - can confirm that works for me (intrigued to know how you figured that out...)

For reference, in node.js land, this translates to:

const { createHash } = require('crypto');
const AccountIdHeader = createHash('sha256').update(userId).digest('hex');

userId can be obtained from the response of the initial login HTTP request.

It was actually mentioned above at https://gist.github.com/khskekec/6c13ba01b10d3018d816706a32ae8ab2?permalink_comment_id=5358133#gistcomment-5358133

@MrAda
Copy link

MrAda commented Oct 10, 2025

@SteveCEvans "I hope that makes sense." Not really. In my version when I get "https://api.libreview.io/llu/connections/" + PATIENT_ID + "/graph", my headers have "Accept", "Authorization", "product" and "version". I changed version to 4.16.0 and it gave me a protocol error. So as I understand it you had to add "Account-Id". The value you are sending out is an sha256 checksum of the PATIENT_ID?

That worked for me. Thanks!!

@SteveCEvans
Copy link

I only send the version header for the login. Once I have the user id and token it’s no longer needed.

@MrAda
Copy link

MrAda commented Oct 11, 2025

@SteveCEvans I'll give that a try.

@xfoguet
Copy link

xfoguet commented Oct 13, 2025

For all those GOphers:

// getAccountID returns the account ID for the given user ID
func getAccountID(userID string) string {
	hash := sha256.Sum256([]byte(userID))
	return hex.EncodeToString(hash[:])
}

@gjkoolen
Copy link

I struggled with URL's, but I got it to work.
So I summarize here.
(I live in Europe)
To request the jwt token and Patient_ID, I use POST to "https://api-eu.libreview.io/llu/auth/login"
For client info including latest glucose level, I use GET to "https://api-eu.libreview.io/llu/connections/"
where I use headers:
headers = {
"Accept": "application/json",
"product": "llu.android",
"version": "4.16",
"Authorization": f"Bearer {jwt_token}",
"Account-Id" : Account_ID
}

Where Account_ID is the SHA256 digest of the Patient_ID.
I am very happy with the contributions from this community!

@MrAda
Copy link

MrAda commented Oct 31, 2025

@gjkoolen I will have to try this as my tool is broken now on getting user information. Funny situation that my tablet doesn't seem to be affected. It may have something to do with what whatever version of Android I am running?

@MrAda
Copy link

MrAda commented Oct 31, 2025

So from what I am seeing the url "https://api.libreview.io/user" is not being called any more?

I was folling this order:
http://api.libreview.io/llu/auth/login (this gets the TOKEN)
http://api.libreview.io/user (this gets DEVICE, EMAIL, FIRSTNAME, LASTNAME, PATIENT_ID)
http://api.libreview.io/account (I think this is where we get an Account_Id)
http://api.libreview.io/llu/connections (Here is where we are suppose to use the encyrpted Account_Id)
http://api.libreview.io/llu/connections/<PATIENT_ID>/graph
http://api.libreview.io/llu/connections/<PATIENT_ID>/logbook
http://api.libreview.io/llu/notifications/settings/<CONNECTION_ID> (Doesn't work for me)
http://api.libreview.io/llu/config/country?country=us

Mine crashes on "user" with a 302 error. So I need the PATIENT_ID/Account_ID before I actually get it from "user". Confusing.

@sgmoore
Copy link

sgmoore commented Oct 31, 2025

@MrAda

http://api.libreview.io/user (this gets DEVICE, EMAIL, FIRSTNAME, LASTNAME, PATIENT_ID)
http://api.libreview.io/account (I think this is where we get an Account_Id)

I never used either of these (nor seen them used anywhere).

As you can see from the very first message in this gist, step 1 will normally1 return a response with your user details , looking something like

{
  "status": 0,
  "data": {
    "user": {
      "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "firstName": "John",
      ...

and it is this id which you need to encrypt for use with llu/connections etc.

Footnotes

  1. I say normally, because sometimes the response from step 1 is a redirect to an intermediate step (like accepting new Terms and Conditions etc) and you need to perform another api post to complete these step(s) until you get the full response. If your software does not handle those intermediate steps, you may have to log into the official LibreLinkup app in order to get passed that stage.

@gjkoolen
Copy link

Thanks @sgmoore
In addition: after Oct 8, I had to start my LibreLinkUp Android app, to read and accept the new terms of use.
After that, I got correct responses from my https requests.

@MrAda
Copy link

MrAda commented Nov 1, 2025

Thanks @sgmoore In addition: after Oct 8, I had to start my LibreLinkUp Android app, to read and accept the new terms of use. After that, I got correct responses from my https requests.

Gosh that worked! my code is working again.

@MrAda
Copy link

MrAda commented Nov 1, 2025

@sgmoore I like that you have a simpler interface. I will look into it.

@MrAda
Copy link

MrAda commented Nov 1, 2025

@sgmoore I got things to work again. Your suggestion helped a lot. Do I new that new header "Account-Id" for every command after logging in or only on connections?

@sgmoore
Copy link

sgmoore commented Nov 1, 2025

@MrAda

I use "Account-Id" for every command after logging in.

@rollkuo
Copy link

rollkuo commented Nov 5, 2025

Hi! I'm building an app to get the LibreLinkUp data but it can only obtain ~142 records. Does anyone know if I can get my full history of my CGM data? Also, I started using my first CGM in Taipei a month ago, but I returned to the US and activated my 2nd CGM with region setting as US. Why do my returned records still have a timestamp in the TPE time zone? How can I fix it?

@MrAda
Copy link

MrAda commented Nov 5, 2025

@rollkuo I don't think any of us have figured out to get all the data programmatically yet. You can go to LibreLinkUp on the web and download your csv data and then incorporate that into your app. Not optimal but it is what is available. You may have noticed that when you poll to get data from the API it is around 30 minutes in the past, no current data. I complained to Abbott that if I was being watched by a friend and I was plunging in Blood Glucose I could be in a serious medical event which could be tragic.

@sgmoore
Copy link

sgmoore commented Nov 5, 2025

You may have noticed that when you poll to get data from the API it is around 30 minutes in the past, no current data

The data you get from the /llu/connections/{patientId}/graph endpoint should contain the current reading (or more accurately the last blood glucose value uploaded) in data/Connection/glucoseMeasurement or data/Connection/glucoseItem (And before you ask, I don't know what the difference between these two is)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment