@unavatar/core 3.25.6 → 3.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  - [Introduction](#introduction)
6
6
  - [Quick start](#quick-start)
7
+ - [Attribution](#attribution)
8
+ - [How to add attribution](#how-to-add-attribution)
9
+ - [Remove attribution](#remove-attribution)
7
10
  - [Authentication](#authentication)
8
11
  - [Pricing](#pricing)
9
12
  - [Cache](#cache)
@@ -62,29 +65,95 @@
62
65
  - [Response Format](#response-format)
63
66
  - [Response Headers](#response-headers)
64
67
  - [Response Errors](#response-errors)
68
+ - [Contact](#contact)
65
69
 
66
70
  ---
67
71
 
72
+ Last updated on April 29, 2026
73
+
68
74
  ## Introduction
69
75
 
70
76
  Welcome to **unavatar.io**, the ultimate avatar service that offers everything you need to easily retrieve user avatars:
71
77
 
78
+ - **Versatile**: A wide range of platforms and services including [TikTok](https://unavatar.io/docs#tiktok), [Instagram](https://unavatar.io/docs#instagram), [YouTube](https://unavatar.io/docs#youtube), [X/Twitter](https://unavatar.io/docs#xtwitter), [Gravatar](https://unavatar.io/docs#gravatar), etc., meaning you can rule all of them just querying against unavatar.
79
+
80
+ - **Speed**: Designed to be fast and efficient with a 91% cache hit rate, serving 12.5 TB of data across 382M requests.
81
+
82
+ - **Optimize**: All the images are not only compressed on-the-fly to reduce their size and save bandwidth, but also optimized to maintain a high-quality ratio. They are ready for immediate use, enhancing the overall optimization of your website or application.
83
+
84
+ - **Integration**: The service seamlessly incorporates into your current applications or websites with ease. We offer straightforward documentation and comprehensive support to ensure a quick and effortless onboarding experience.
85
+
72
86
  It's proudly powered by [microlink.io](https://microlink.io/), the headless browser API that handles all the heavy lifting behind the scenes to ensure your avatars are always ready.
73
87
 
74
88
  ## Quick start
75
89
 
76
- The service is exposed in **unavatar.io** via provider endpoints:
90
+ The service is exposed in **unavatar.io** via endpoints.
77
91
 
78
- - an **email (auto-detect)**: [unavatar.io/hello@microlink.io](https://unavatar.io/hello@microlink.io) tries Gravatar, then GitHub
79
- - an **email** via Gravatar: [unavatar.io/gravatar/hello@microlink.io](https://unavatar.io/gravatar/hello@microlink.io)
80
- - a **Gravatar SHA-256** (same email, pre-hashed): [unavatar.io/gravatar/b1f507c7a29adfa84eaa521036774b0577c58f23f2f3f42e068d6ac256cffae2](https://unavatar.io/gravatar/b1f507c7a29adfa84eaa521036774b0577c58f23f2f3f42e068d6ac256cffae2)
81
- - an **email** via GitHub: [unavatar.io/github/sindresorhus@gmail.com](https://unavatar.io/github/sindresorhus@gmail.com)
92
+ An endpoint determines how the avatar is looked up and what parameters are required.
93
+
94
+ For example, you can get an avatar for:
95
+
96
+ - an **email**: [unavatar.io/email/hello@microlink.io](https://unavatar.io/email/hello@microlink.io)
82
97
  - an **username**: [unavatar.io/github/kikobeats](https://unavatar.io/github/kikobeats)
83
- - a **domain**: [unavatar.io/google/reddit.com](https://unavatar.io/google/reddit.com)
98
+ - a **domain**: [unavatar.io/domain/reddit.com](https://unavatar.io/domain/reddit.com)
99
+
100
+ Read [providers](https://unavatar.io/docs#providers) to know more. Each provider can accept different parameters.
101
+
102
+ ## Attribution
103
+
104
+ Free plans require attribution. Upgrade to any paid plan to remove this requirement.
105
+
106
+ Attribution ensures proper domain verification and helps us keep unavatar.io free for the community.
107
+
108
+ Your attribution link:
109
+
110
+ - Must be on your production site (not staging or localhost).
111
+ - Must be publicly accessible and viewable in browsers.
112
+ - Must not use rel="nofollow", redirects, or obfuscation.
113
+
114
+ ### How to add attribution
115
+
116
+ Add this link on any page or surface displaying unavatar.io avatars:
117
+
118
+ ```html
119
+ [Avatars provided by Unavatar](https://unavatar.io)
120
+ ```
84
121
 
85
- Use `/:provider/:key` for provider-specific lookups, or pass an email as the only path segment for automatic resolution. You can read more in [Email avatars](https://unavatar.io/email) and [providers](https://unavatar.io/docs#providers).
122
+ **Example**
86
123
 
87
- For **Gravatar**, `key` can be a plain email or a precomputed identifier: emails are trimmed, lowercased, and hashed with **SHA-256** before calling Gravatar. Values that already look like a **64-character hex SHA-256** or **32-character hex MD5** are sent as-is (hex is normalized to lowercase).
124
+ ```html
125
+
126
+ ![Kiko](https://unavatar.io/github/kikobeats)
127
+
128
+ ![Joseba](https://unavatar.io/x/josebaseba)
129
+
130
+ <p class="attribution">
131
+
132
+ [Avatars provided by Unavatar](https://unavatar.io)
133
+
134
+ </p>
135
+ ```
136
+
137
+ **Valid placements**
138
+
139
+ Site footer, about page, credits page, or any page that renders avatars.
140
+
141
+ **Mobile apps and non-web products**
142
+
143
+ If avatars are displayed in a mobile app, desktop app, browser extension, email, or any non-web surface, add the attribution link on your app's marketing site, app store listing description, or credits screen.
144
+
145
+ **Requirements for attribution to be valid**
146
+
147
+ We reserve the right to revoke free-tier access for any website or product that does not comply with the attribution requirements described in this document:
148
+
149
+ - Double-check the href. It must point to [https://unavatar.io](https://unavatar.io/) directly — no redirects, no URL shorteners, no tracking wrappers.
150
+ - Make sure it's crawlable. The link must be present in the rendered HTML and not blocked by robots.txt, authentication, or region gating.
151
+ - Avoid nofollow or noindex. We need a standard, followable link.
152
+ - target="\_blank" is allowed.
153
+
154
+ ### Remove attribution
155
+
156
+ Attribution is only required on the free plan. [Upgrade to the PRO plan](https://unavatar.io/checkout) to remove the requirement.
88
157
 
89
158
  ## Authentication
90
159
 
@@ -98,9 +167,13 @@ curl "https://unavatar.io/github/kikobeats" -H "x-api-key: YOUR_API_KEY"
98
167
 
99
168
  ```javascript
100
169
  await fetch('https://unavatar.io/github/kikobeats', {
170
+
101
171
  headers: {
172
+
102
173
  'x-api-key': 'YOUR_API_KEY'
174
+
103
175
  }
176
+
104
177
  })
105
178
  ```
106
179
 
@@ -108,8 +181,11 @@ await fetch('https://unavatar.io/github/kikobeats', {
108
181
  import requests
109
182
 
110
183
  response = requests.get(
184
+
111
185
  'https://unavatar.io/github/kikobeats',
186
+
112
187
  headers={'x-api-key': 'YOUR_API_KEY'}
188
+
113
189
  )
114
190
  ```
115
191
 
@@ -119,24 +195,33 @@ package main
119
195
  import "net/http"
120
196
 
121
197
  func main() {
198
+
122
199
  req, _ := http.NewRequest("GET", "https://unavatar.io/github/kikobeats", nil)
200
+
123
201
  req.Header.Set("x-api-key", "YOUR_API_KEY")
124
202
 
125
203
  resp, _ := http.DefaultClient.Do(req)
204
+
126
205
  defer resp.Body.Close()
206
+
127
207
  }
128
208
  ```
129
209
 
130
210
  ```ruby
131
211
  require 'net/http'
212
+
132
213
  require 'uri'
133
214
 
134
215
  uri = URI('https://unavatar.io/github/kikobeats')
216
+
135
217
  request = Net::HTTP::Get.new(uri)
218
+
136
219
  request['x-api-key'] = 'YOUR_API_KEY'
137
220
 
138
221
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
222
+
139
223
  http.request(request)
224
+
140
225
  end
141
226
  ```
142
227
 
@@ -144,11 +229,15 @@ end
144
229
  $ch = curl_init('https://unavatar.io/github/kikobeats');
145
230
 
146
231
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
232
+
147
233
  'x-api-key: YOUR_API_KEY',
234
+
148
235
  ]);
236
+
149
237
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
150
238
 
151
239
  $response = curl_exec($ch);
240
+
152
241
  curl_close($ch);
153
242
  ```
154
243
 
@@ -166,7 +255,9 @@ Rate limit status can be verified using these response headers:
166
255
  $ curl -I https://unavatar.io/github/kikobeats
167
256
 
168
257
  x-rate-limit-limit: 25
258
+
169
259
  x-rate-limit-remaining: 24
260
+
170
261
  x-rate-limit-reset: 1744243200
171
262
  ```
172
263
 
@@ -196,7 +287,9 @@ The proxy tier used is returned in the `x-proxy-tier` response header, and the t
196
287
  $ curl -I -H "x-api-key: YOUR_API_KEY" https://unavatar.io/instagram/kikobeats
197
288
 
198
289
  x-pricing-tier: pro
290
+
199
291
  x-proxy-tier: origin
292
+
200
293
  x-unavatar-cost: 1
201
294
  ```
202
295
 
@@ -230,6 +323,7 @@ To check the cache status in real requests, inspect these response headers:
230
323
  $ curl -I -H "x-api-key: YOUR_API_KEY" "https://unavatar.io/github/kikobeats?ttl=1h"
231
324
 
232
325
  cache-control: public, max-age=3600
326
+
233
327
  x-cache-status: HIT
234
328
  ```
235
329
 
@@ -469,6 +563,10 @@ Available inputs:
469
563
  - SHA-256 hash, e.g., [unavatar.io/gravatar/b1f507c7a29adfa84eaa521036774b0577c58f23f2f3f42e068d6ac256cffae2](https://unavatar.io/gravatar/b1f507c7a29adfa84eaa521036774b0577c58f23f2f3f42e068d6ac256cffae2)
470
564
  - MD5 hash, e.g., [unavatar.io/gravatar/3f293df98a473eae038deabe430a1e30](https://unavatar.io/gravatar/3f293df98a473eae038deabe430a1e30)
471
565
 
566
+ When you pass an email address directly in the URL, it is visible in plain text — both in server logs and to any intermediary that inspects the request.
567
+
568
+ To avoid this, pass a pre-computed `MD5` or `SHA256` hash of the email instead. Unavatar detects the hash automatically and routes it to Gravatar, which natively supports both hash formats.
569
+
472
570
  ### Instagram
473
571
 
474
572
  Get any Instagram user's profile picture by their username. No authentication or API tokens needed — just pass the username.
@@ -725,11 +823,17 @@ These headers help you understand pricing, limits, and request diagnostics.
725
823
  $ curl -I -H "x-api-key: YOUR_API_KEY" https://unavatar.io/github/kikobeats
726
824
 
727
825
  x-pricing-tier: pro
826
+
728
827
  x-timestamp: 1744209600
828
+
729
829
  x-unavatar-cost: 1
830
+
730
831
  x-proxy-tier: origin
832
+
731
833
  x-rate-limit-limit: 50
834
+
732
835
  x-rate-limit-remaining: 49
836
+
733
837
  x-rate-limit-reset: 1744243200
734
838
  ```
735
839
 
@@ -770,4 +874,4 @@ Expected errors are known operational cases returned with stable codes.
770
874
 
771
875
  ## Contact
772
876
 
773
- If you have any suggestion or bug to report, please contact to ust mailing to [hello@unavatar.io](mailto:hello@unavatar.io).
877
+ If you have a suggestion or need to report a bug, contact us at <hello@unavatar.io>.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@unavatar/core",
3
3
  "description": "Get unified user avatar from social networks, including Instagram, SoundCloud, Telegram, Twitter, YouTube & more.",
4
4
  "homepage": "https://unavatar.io",
5
- "version": "3.25.6",
5
+ "version": "3.26.0",
6
6
  "main": "src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js",
@@ -157,7 +157,7 @@
157
157
  "devDependencies": {
158
158
  "@commitlint/cli": "latest",
159
159
  "@commitlint/config-conventional": "latest",
160
- "ava": "latest",
160
+ "ava": "7",
161
161
  "c8": "latest",
162
162
  "cheerio": "latest",
163
163
  "ci-publish": "latest",
@@ -35,6 +35,7 @@ const providersBy = {
35
35
  'steam',
36
36
  'substack',
37
37
  'telegram',
38
+ 'thingiverse',
38
39
  'threads',
39
40
  'tiktok',
40
41
  'tumblr',
@@ -85,6 +86,7 @@ module.exports = ctx => {
85
86
  steam: require('./steam')(ctx),
86
87
  substack: require('./substack')(ctx),
87
88
  telegram: require('./telegram')(ctx),
89
+ thingiverse: require('./thingiverse')(ctx),
88
90
  threads: require('./threads')(ctx),
89
91
  tiktok: require('./tiktok')(ctx),
90
92
  tumblr: require('./tumblr')(ctx),
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ const getProfileUrl = input => `https://www.thingiverse.com/${input}`
4
+
5
+ const getAvatarUrl = ({ getOgImage, $ }) =>
6
+ new URL(getOgImage($)).searchParams.get('url')
7
+
8
+ module.exports = ({ createHtmlProvider, getOgImage }) =>
9
+ createHtmlProvider({
10
+ name: 'thingiverse',
11
+ url: getProfileUrl,
12
+ getter: $ => getAvatarUrl({ getOgImage, $ })
13
+ })
14
+
15
+ module.exports.getAvatarUrl = getProfileUrl
16
+ module.exports.getAvatarUrlFromMarkup = getAvatarUrl