CodeWorlds
Back to collections
Guide16 min readCodeWorlds Team

Jina AI, model weights under a non-commercial licence

Jina AI ships embedding and reranker weights on Hugging Face, yet nearly all carry a cc-by-nc-4.0 tag. Licensing, per-token pricing and plain HTTP over an SDK.

Jina AI, model weights under a non-commercial licence

Jina AI ships text embedding models and rerankers available both through a paid API and as weights on Hugging Face. The weights look open, yet nearly the entire current family carries a cc-by-nc-4.0 tag, a licence that forbids commercial use. That is the first thing to check before anyone on the team plans to run these models on their own hardware.

What Jina AI actually sells today

The public model listing at api.jina.ai/v1/models returns 29 entries and it is the single best picture of the offering, because the marketing page does not render without JavaScript. The listing holds four groups.

The first is text embedding models: jina-embeddings-v5-text-small and jina-embeddings-v5-text-nano, the earlier jina-embeddings-v4 and jina-embeddings-v3, the whole jina-embeddings-v2-base-* family in English, German, Spanish, Chinese and code variants, plus separate jina-code-embeddings-0.5b and jina-code-embeddings-1.5b. The second is rerankers: jina-reranker-v3.5, jina-reranker-v3, jina-reranker-m0 which accepts an image alongside text, jina-reranker-v2-base-multilingual and three old v1 variants. The third is multimodal models: jina-clip-v2, jina-embeddings-v5-omni-small and jina-embeddings-v5-omni-nano accepting text, image, video and audio, plus jina-vlm. The fourth covers HTML to markdown conversion: ReaderLM-v2, reader-lm-0.5b and reader-lm-1.5b.

Context windows differ sharply and that tends to surprise people migrating between versions. jina-embeddings-v3 takes 8192 tokens, jina-embeddings-v4 and jina-embeddings-v5-text-small take 32768 each, and jina-embeddings-v5-text-nano is back to 8192. Rerankers have the most: jina-reranker-v3 declares 134144 tokens and jina-reranker-v3.5 declares 131072. The old jina-reranker-v2-base-multilingual has only 1024 tokens, which for a typical documentation chunk means truncation halfway through. ReaderLM-v2 declares 524288 tokens, because its job is to swallow a whole raw page.

On top of that sit two services with no model in the name: the page reader at r.jina.ai and the search endpoint at s.jina.ai.

The weight licence, the core of the matter

I checked the Hugging Face metadata through the public API and the result is unambiguous. The license:cc-by-nc-4.0 tag is carried by jina-embeddings-v3, jina-embeddings-v5-text-small, jina-embeddings-v5-text-nano, jina-embeddings-v5-omni-small, jina-reranker-v3, jina-reranker-v3.5, jina-reranker-v2-base-multilingual, jina-clip-v2, jina-colbert-v2, jina-code-embeddings-1.5b, jina-vlm, ReaderLM-v2 and reader-lm-1.5b. Creative Commons Attribution NonCommercial 4.0 forbids using the work in a manner primarily directed toward commercial advantage. Production search inside a paid product falls squarely under that ban.

The exception is the second generation from 2023. jina-embeddings-v2-base-en and jina-embeddings-v2-small-en carry the license:apache-2.0 tag. Those are the oldest and weakest models in the family, but the only ones you may run yourself inside a revenue-generating product without asking anyone.

A separate case is jina-embeddings-v4. The Hugging Face metadata has no licence tag at all, so a dependency scanner sees an empty field and usually says nothing. The repository, however, contains a LICENSE file holding a text titled "Qwen RESEARCH LICENSE AGREEMENT" with a release date of 19 September 2024, issued by Alibaba Cloud. Clause 2a grants rights "FOR NON-COMMERCIAL PURPOSES ONLY" and clause 1i defines "Non-Commercial" as research or evaluation use only. The model was built on Qwen2.5-VL, so it inherited the base model's licence. A missing tag is worse here than a tag forbidding commerce, because it lulls you into inattention.

There is a second side to the same inconsistency. Most models tagged cc-by-nc-4.0 carry no licence file in the repository at all. I listed the contents of the jina-embeddings-v3 and jina-reranker-v3 repositories: weights, tokenizer, configuration and README are there, but no LICENSE file. The licence exists purely as a field in the model card header. If someone pulls the weights with a script and archives the directory, no trace of the restriction survives in the archive.

It pays to check this yourself before every model upgrade, because the field can change between releases.

Code
Bash
# licence tag from metadata, license field from the model card, and licence files in the repo
for m in jinaai/jina-embeddings-v5-text-small \
         jinaai/jina-embeddings-v4 \
         jinaai/jina-embeddings-v3 \
         jinaai/jina-embeddings-v2-base-en \
         jinaai/jina-reranker-v3.5; do
  echo "== $m"
  curl -s "https://huggingface.co/api/models/$m" \
    | jq -r '[
        (.tags[] | select(startswith("license"))) // "NO-TAG",
        (.cardData.license // "no-field"),
        ([.siblings[].rfilename | select(test("LICEN";"i"))] | join(",") // "no-file")
      ] | @tsv'
done

The practical conclusion is simple. Jina AI weights are fine for quality comparison in a notebook, for research work and for a prototype nobody sells. For a revenue-generating product you are left with the paid API or another vendor's base model. The company does sell commercial licences through a contact form, but the price of such a licence is not public, so it cannot be quoted here.

The jina package is an old framework, not an SDK

Anyone looking for a client library most often lands on the PyPI package named jina, and that is a dead end. The newest version of that package is 3.34.0 uploaded on 24 March 2025, meaning over a year without a release. The registry description reads "Multimodal AI services and pipelines with cloud-native stack: gRPC, Kubernetes, Docker, OpenTelemetry, Prometheus, Jaeger", which has nothing to do with calling an embedding model. It is a framework for building distributed multimodal services, a product from an earlier stage of the company's life.

The address in the home_page field points to github.com/jina-ai/jina, and that redirects to github.com/jina-ai/serve. The repository was renamed, and the release feed confirms that the last tag is v3.34.0 from 24 March 2025. The license field in the PyPI registry reads "Apache 2.0" and it agrees with the LICENSE file in the repository: the full Apache 2.0 text across 193 lines, preceded by the header "Copyright 2020-2021 Jina AI Limited". Here three sources say the same thing.

On the npm side it is worse. The package named jina in the npm registry does not come from this company: it belongs to the alismithy account, sits at version 1.0.22 and carries an ISC licence. Installing it grants no access to any model. The official JavaScript client is called jinaai, sits at version 0.2.20 released on 25 January 2024, carries an Apache-2.0 licence and has a single dependency, tslib in the ^2.5.3 range. The jina-ai/jinaai-js repository exists and holds a LICENSE file with the Apache 2.0 text. Two and a half years without a release means the package knows nothing about v4 or v5 models.

On the Python side there is no official client today at all. The names jina-ai, jina-embeddings and jina-reranker all return 404 on PyPI.

How to integrate today

With no package available, plain HTTP is what remains, and that is the answer to the SDK question. It is neither a workaround nor a stopgap, it is today's primary path. Both endpoints require an Authorization header and return 401 with the body AUTH_MISSING_API_KEY without one.

Code
Bash
# embeddings: model, input, task, plus optional embedding_type and normalized
curl -s https://api.jina.ai/v1/embeddings \
  -H "Authorization: Bearer $JINA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jina-embeddings-v3",
    "task": "retrieval.passage",
    "embedding_type": "float",
    "normalized": true,
    "input": [
      "A reranker reorders the results returned by a search engine.",
      "Embeddings turn text into a vector of floating point numbers."
    ]
  }'

The task field accepts one of five values and those are not names invented by the documentation. The config.json file of jina-embeddings-v3 lists them in the lora_adaptations field: retrieval.query, retrieval.passage, separation, classification and text-matching. Each corresponds to a separate LoRA adapter attached to a shared core of 24 layers with a hidden size of 1024. Query and document must be encoded with different values, retrieval.query for the first and retrieval.passage for the second, otherwise the whole benefit of the arrangement is lost. The same configuration file lists the permitted vector truncations in the matryoshka_dimensions field: 32, 64, 128, 256, 512, 768 and 1024.

Reranking lives at a separate address and accepts a different set of fields.

Code
Bash
# reranking: model, query, documents, top_n, return_documents
curl -s https://api.jina.ai/v1/rerank \
  -H "Authorization: Bearer $JINA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "jina-reranker-v3",
    "query": "how to shorten an embedding vector",
    "top_n": 3,
    "return_documents": false,
    "documents": [
      "Matryoshka lets you truncate the vector to 256 dimensions.",
      "A Docker container is built with the docker build command.",
      "A LoRA adapter changes model behaviour without touching core weights."
    ]
  }'

Setting return_documents to false shrinks the response to indices and scores alone, which makes a visible difference in payload size at fifty candidates. The top_n field trims the list server-side but does not change billing, because every token you send is counted.

Running the weights locally, if the licence permits it, looks like this. The example below uses parameters documented in the jina-embeddings-v3 model card.

Code
Python
from sentence_transformers import SentenceTransformer

# trust_remote_code is required because the repo ships its own custom_st.py module
model = SentenceTransformer("jinaai/jina-embeddings-v3", trust_remote_code=True)

# task picks the LoRA adapter, truncate_dim shortens the vector per matryoshka_dimensions
passages = model.encode(
    ["Embeddings turn text into a vector of numbers."],
    task="retrieval.passage",
    truncate_dim=256,
)

query = model.encode(["what are embeddings"], task="retrieval.query", truncate_dim=256)
print(passages.shape, query.shape)

Vectors from this model then land in a vector database, for instance in Qdrant or in pgvector if the data already sits in PostgreSQL. The truncated dimension has to be chosen before the collection is created, because changing the dimension forces a full recomputation of the whole set.

Reader, a page turned into markdown

The reader at r.jina.ai is the most accessible part of the offering, because it works without a key. I verified this with a direct call: the address https://r.jina.ai/https://example.com returns 200 and markdown ready to hand to a language model. The search endpoint at s.jina.ai does require a key and returns 401 with the error name AuthenticationRequiredError without one.

Reader behaviour is driven by headers. Below are names read from the client panel, not from memory.

Code
Bash
# markdown with a links summary, bypassing the cache, cutting out page elements
curl -s "https://r.jina.ai/https://example.com" \
  -H "X-Respond-With: markdown" \
  -H "X-With-Links-Summary: true" \
  -H "X-Target-Selector: main" \
  -H "X-Remove-Selector: nav, footer" \
  -H "X-No-Cache: true" \
  -H "X-Token-Budget: 4000" \
  -H "X-Timeout: 20"

# the same content as JSON instead of plain text
curl -s "https://r.jina.ai/https://example.com" -H "Accept: application/json"

The JSON response has a fixed shape and a data.usage.tokens field with the token count, worth logging from day one.

Code
JSON
{
  "code": 200,
  "status": 20000,
  "data": {
    "title": "Example Domain",
    "url": "https://example.com/",
    "content": "This domain is for use in documentation examples...",
    "publishedTime": "Tue, 18 Aug 2026 20:06:42 GMT",
    "warning": "This is a cached snapshot of the original page, consider retry with caching opt-out.",
    "httpStatus": 200,
    "usage": { "tokens": 29 }
  }
}

The warning field in that response matters. By default the reader hands back a stored copy of the page rather than a fresh fetch. The date in publishedTime in my test was four days older than the day of the call. To collect frequently changing content you need X-No-Cache or X-Cache-Tolerance with a number of seconds. The header set also covers X-Wait-For-Selector for browser-rendered pages, X-Proxy-Url for your own proxy, X-Locale and X-Set-Cookie for content behind a login, plus a separate group of X-Md-Heading-Style, X-Md-Link-Style, X-Md-Bullet-List-Marker, X-Md-Em-Delimiter and X-Md-Hr controlling output formatting.

If the job is walking an entire site rather than a single address, Jina's reader has no scheduler and no queue, and Firecrawl is the better reach. Jina does well where the list of addresses is already known.

Pricing and the bill for a million tokens

Here a verification problem appears that has to be named directly. The public pricing page is a single-page application and the raw HTML contains not a single amount. The only number extractable from it is an auto-recharge setting described as "Top up when < 1M Tokens", which is a top-up threshold, not the size of the free plan. I did not confirm the free plan size nor what happens once it runs out, and I will not guess.

Unit prices, on the other hand, are available machine-readably. The /v1/models listing returns a pricing object for every model with a prompt field inside. For 27 of the 29 models, including all v3, v4 and v5-small embeddings and all rerankers, the value is 0.00000005. For jina-embeddings-v5-text-nano and jina-embeddings-v5-omni-nano it is 0.00000002. The completion field is zero in every case, so only input tokens are billed. That number comes from a single source, the API itself, and I have no second public figure to cross-check it against.

Converting to a million tokens: 1,000,000 times 0.00000005 gives 0.05 dollars. Indexing a million tokens of text costs five cents, or two cents with a nano model. A million tokens is roughly seven hundred thousand words, meaning about ten mid-sized books or a sizeable product documentation set.

Reranking is billed at the same rate but behaves completely differently, because indexing happens once while reranking happens on every query. At fifty candidates of five hundred tokens each, a single query consumes 25,000 tokens, which is 0.00125 dollars. A thousand queries a day is 1.25 dollars a day and around 37.50 dollars over a thirty-day month. The reranking bill overtakes the indexing bill at quite modest traffic, and that is the right axis for cost planning, not the price of indexing the corpus.

Jina AI against other embedding families

Every family in this comparison turns text into a vector, and quality differences between them are small today and shift quickly. The durable difference lies elsewhere: in whether you can escape the token bill at all by running the model yourself.

FamilyWeights publishedWeight licenceCommercial self-hostingVendor API
Jina v5, v4, v3yescc-by-nc-4.0, Qwen Research for v4noyes
Jina v2 from 2023yesApache 2.0yesyes
BGE from BAAIyesMITyesnone of its own
all-MiniLM and kinyesApache 2.0yesnone of its own
Voyage AInono weightsnot applicableyes
Cohere Embednono weightsnot applicableyes
OpenAI Embeddingsnono weightsnot applicableyes

I checked the licence tags of three comparison models: BAAI/bge-m3 and BAAI/bge-large-en-v1.5 carry license:mit, and sentence-transformers/all-MiniLM-L6-v2 carries license:apache-2.0. The families covered in the BGE and Sentence Transformers write-ups are therefore the only ones here that offer both public weights and a licence permitting you to sell a product.

Voyage AI, Cohere Embed and OpenAI Embeddings publish no weights for their current models at all. Their position is at least honest: you pay per token and you know it from the start, without the illusion that you will one day move this onto your own hardware. Jina occupies the middle and most misleading spot, because the weights download with one command yet only a prototype may legally be built on them.

Vendor lock-in risk is the same with any paid API and does not depend on how many fields the request has. Migration means recomputing the entire corpus with a different model, because vectors from two different models are not comparable. The cost of migration is the cost of reindexing, so five cents per million tokens is both the price of entry and the price of exit.

Common mistakes

Installing the jina package from npm hoping for an API client. That package does not come from Jina AI, it has a different author and an ISC licence. The official JavaScript client is called jinaai and has had no release since January 2024.

Installing the jina package from PyPI with the same intent. It is a framework for multimodal services, last released in March 2025, with the repository renamed to jina-ai/serve. It does not call embedding models.

Assuming that a missing licence tag on jina-embeddings-v4 means no restrictions. The repository holds a LICENSE file with the Qwen Research License text, which permits research and evaluation use only.

Encoding query and document with the same task value. The model has five separate LoRA adapters and mixing them up cancels the benefit of asymmetric encoding.

Relying on the reader's default behaviour for volatile content. Without X-No-Cache or X-Cache-Tolerance you get a stored copy, which the warning field in the JSON response announces.

Budgeting solely on indexing cost. Reranking is billed at the same per-token rate but repeats on every query, and it is what drives the bill.

Changing truncate_dim after the vector database collection has been created. Vector dimension is part of the schema and changing it forces a full recomputation.

FAQ

May I use Jina AI weights in a paid product?

For the current models, no. Generations v3, v4 and v5 plus every reranker other than the v1 variants carry a non-commercial licence, with v4 additionally under the Qwen Research licence rather than Creative Commons. Commercially you may use the jina-embeddings-v2-base-en and jina-embeddings-v2-small-en weights under Apache 2.0, or buy API access.

Is there an official SDK package?

For Python there is none, the names jina-ai, jina-embeddings and jina-reranker all return 404 on PyPI. For JavaScript there is jinaai at version 0.2.20 from 25 January 2024, which knows nothing about v4 or v5 models. Today's path is plain HTTP calls to api.jina.ai/v1/embeddings and api.jina.ai/v1/rerank.

What does indexing a million tokens cost?

Five cents at the 0.00000005 per-token rate that the /v1/models listing returns for v3, v4 and v5-small embeddings. Two cents with jina-embeddings-v5-text-nano. I did not confirm the free plan size, because the pricing page does not render without JavaScript.

Does the page reader work without an API key?

Yes, r.jina.ai returns content without an Authorization header, which I verified directly. The s.jina.ai search endpoint does require a key and returns 401 without one. The reader hands back a stored copy of the page by default and signals this in the warning field.

How does a reranker differ from an embedding model?

An embedding model encodes each text separately, so vectors can be computed once and kept in a database. A reranker looks at the query and document pair together, gives better ordering, but cannot be precomputed. In practice you combine both: embeddings pick a few dozen candidates and the reranker reorders them.

What happened to the jina package and the jina-ai/jina repository?

The repository was renamed to jina-ai/serve and the old address redirects to the new one. The jina PyPI package sits at version 3.34.0 from 24 March 2025. It is a separate product, a framework for multimodal services, not a client for today's embedding models.

Read next

We use cookies to enhance your experience on the site