Tika App (Command Line & GUI)
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Baseline date: 2026-10-12. This page was written against Apache Tika 4.1.0 (the latest release on Maven Central on that
date), with the 3.3.x differences noted, Java 21 and later for the examples (Tika 4.x needs Java 17), Spring Boot 4.x on
Spring Framework 7 for the integration pages, and the Docker image apache/tika:4.1.0 for the service pages. tika-app
is the Tika you can use without writing code: one command that parses a file, a URL or standard input and prints the
text, the metadata, the media type or the language, a small desktop window for drag-and-drop, and, since 4.0, a front
end to Tika Pipes that processes whole directories in forked JVMs. This page covers the three modes, every option of the
4.1.0 release, the options that were removed, and the Bookshelf intake desk using the tool to look at the files it
receives.
|
The tika-app CLI is still in flux for 4.x
The official 4.1.x CLI page opens with the warning that the command line interface "is still in flux for 4.x". Options
and behavior may change between 4.x releases. The same page says the authoritative option list is the |
Related pages: Setup & Installation (the zip distributions and
Java requirement), Content Handlers & Output Formats
(what each output format contains), Metadata (the tk: keys you will see in
the output), Embedded Documents & Recursive Parsing
(-J and unpacking), Configuration (tika-config.json) and
Tika Pipes (the engine behind pipes mode).
How this page was verified: the official tika-app-4.1.0.zip was downloaded from the Apache archive
(https://archive.apache.org/dist/tika/4.1.0/), its SHA-512 checksum was compared with the published .sha512 file,
and it was unzipped into a working directory. Every command on this page that shows output was run from that
distribution with java -jar tika-app-4.1.0.jar on Java 25 (Oracle JDK 25.0.2) on macOS, and the output is copied from
the terminal, shortened only where marked. The option semantics were read from the 4.1.0 source of TikaCLI,
AsyncHelper and the tika-async-cli module (TikaAsyncCLI, PluginsWriter) at the 4.1.0 Git tag. The sample
files are small stand-ins written for this section: a one-heading manuscript.docx (title The Lighthouse Keeper,
author Ana Torres), a one-page catalogue.pdf (785 bytes), the same PDF renamed to renamed-invoice.png, a
password-protected members-only.pdf, a windows-1252 legacy-catalogue.txt, a tiny novel.epub, a Spanish
reviews-es.html, a French reseñas-fr.txt and publisher-email.eml, an e-mail that carries samples.zip. The GUI was
not opened for this page (see The GUI).
What tika-app is
tika-app is a Maven module and a release artifact. Its main class, org.apache.tika.cli.TikaCLI, wraps the same
components the Java pages of this section use: a TikaLoader built from a configuration file, an AutoDetectParser, a
ParseContext and a content handler chosen by an option. Since Tika 4.0 it also wraps PipesForkParser (fork mode) and
the Tika Pipes AsyncProcessor (pipes mode). In short, it is a convenient way to see what Tika will do with a file before
you write code, to script one-off extractions and, in pipes mode, to run a batch.
It runs in three modes. The official page names them standard, GUI and Tika Pipes. Fork mode is an option of the standard mode.
| Mode | What it does | How you get it |
|---|---|---|
Standard |
Parses one or more files, URLs or standard input in the CLI JVM and writes the result to standard output. |
A file, a URL, |
Standard + fork |
Same output, but the parse runs in a forked JVM through |
Add |
GUI |
A Swing window. Drop a file on it and look at its metadata, text, XHTML and recursive JSON. |
|
Tika Pipes |
Processes every file under a directory (or a file list, or any configured pipes iterator) in forked JVMs and writes one output file per input. |
Two directories, |
The mode is picked from the arguments before any option is applied. The following flow is how TikaCLI.main in 4.1.0
decides (help first, then the pipes test, then the standard per-argument loop).
Source: Apache Tika 4.1.x, Tika Command Line Interface
and the 4.1.0 source of TikaCLI.java.
Installing the zip distribution
Tika 4.x ships tika-app as a zip, not as the single fat jar of the 1.x to 3.x lines. The jar inside the zip is a thin
launcher: its manifest has a Class-Path that lists the jars in the adjacent lib/ directory, and pipes mode loads its
fetcher and emitter plugins from the adjacent plugins/ directory. The zip has no top-level directory, so unzip it into
one.
curl -O https://archive.apache.org/dist/tika/4.1.0/tika-app-4.1.0.zip
curl -O https://archive.apache.org/dist/tika/4.1.0/tika-app-4.1.0.zip.sha512
shasum -a 512 tika-app-4.1.0.zip # compare with the content of the .sha512 file
cat tika-app-4.1.0.zip.sha512
unzip -q -d tika-app-4.1.0 tika-app-4.1.0.zip
ls tika-app-4.1.0
Output (the two checksum lines were identical and are shortened here):
e8ffd4b85f08b2c9...25487c8745d tika-app-4.1.0.zip
e8ffd4b85f08b2c9...25487c8745d
LICENSE NOTICE lib plugins tika-app-4.1.0.jar
What is inside (4.1.0):
| Entry | Content |
|---|---|
|
|
|
110 jars, about 57 MB: |
|
The file-system pipes plugin ( |
|
The Apache license and notices. |
The Class-Path entries are resolved relative to the jar, not to the current directory, so java -jar
/opt/tika-app-4.1.0/tika-app-4.1.0.jar works from any working directory. All the examples on this page were run that way
from a directory that held the sample files. The jar on its own does not work. Copied out of the distribution it fails
before reading any argument:
cp tika-app-4.1.0/tika-app-4.1.0.jar /some/other/dir/
java -jar /some/other/dir/tika-app-4.1.0.jar --version
Output:
Error: Unable to initialize main class org.apache.tika.cli.TikaCLI
Caused by: java.lang.NoClassDefFoundError: org/apache/tika/mime/MimeTypeException
This is the NoClassDefFoundError the 4.x FAQ and the CLI page describe. If pipes mode is started from an incomplete
distribution, TikaCLI catches the error and prints an explanation (download the zip, run the jar from inside it); the
standard mode fails in the JVM launcher, as above. The tika-app artifact on Maven Central is the same thin jar plus a
POM with the dependencies, which is how the earlier pages of this section ran TikaCLI on a Maven-built classpath.
A shell alias keeps the commands short. The rest of the page writes tika for it:
alias tika='java -jar /opt/tika-app-4.1.0/tika-app-4.1.0.jar'
tika --version
Output:
Apache Tika 4.1.0
The JVM options go before -jar, as for any Java program: java -Xmx2g -jar tika-app-4.1.0.jar ... sets the heap of
the CLI JVM in standard mode. The forked JVMs of fork mode and pipes mode get their own options through
--fork-jvm-args and --Xmx, described below.
Source: Apache Tika, Download, Apache Tika 4.1.x, Tika Command Line Interface, Installation and Apache Tika 4.1.x, FAQ.
Logging and the convenience-defaults banner
Log lines go to standard error through Log4j 2, so standard output stays clean for redirection and pipes. The bundled
log4j2.xml logs at INFO, and every standard-mode run without --config logs this notice first:
INFO [main] 22:53:16,719 org.apache.tika.cli.TikaCLI As a convenience, TikaCLI has turned on several non-default features
as specified in tika-app/src/main/resources/tika-config-default-single-file.json.
See: TIKA-2374, TIKA-4017, TIKA-4354 and TIKA-4472).
This is not the default behavior in Tika generally or in tika-server.
The notice is accurate and worth reading. Without --config, tika-app loads a bundled configuration that turns on
features the library and tika-server leave off. The file in the 4.1.0 jar is:
{
"parsers": [
{ "default-parser": {} },
{ "pdf-parser": {
"extractActions": true,
"extractInlineImages": true,
"accessCheckMode": "ALLOW_EXTRACTION_FOR_ACCESSIBILITY",
"extractIncrementalUpdateInfo": true,
"parseIncrementalUpdates": true } },
{ "ooxml-parser": {
"includeDeletedContent": true,
"includeMoveFromContent": true,
"extractMacros": true } },
{ "office-parser": { "extractMacros": true } }
]
}
So tika-app shows PDF actions, inline images and incremental updates, and Word’s deleted and moved text and macros, by
default. That is useful when you are inspecting a file, and it is the reason the same file can give a little more output
in tika-app than in your own AutoDetectParser code. Pass --config= with your production configuration when you want
to see exactly what your service will see. The pipes mode template has the same parser settings (see
Defaults of pipes mode).
To keep only warnings and errors, point Log4j at your own file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- quiet-log4j2.xml: only WARN and above, on standard error -->
<Configuration status="WARN">
<Appenders>
<Console name="stderr" target="SYSTEM_ERR">
<PatternLayout pattern="%-5p %c{1} %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="warn"><AppenderRef ref="stderr"/></Root>
</Loggers>
</Configuration>
java -Dlog4j.configurationFile=quiet-log4j2.xml -jar tika-app-4.1.0.jar -t catalogue.pdf
Output (standard error was empty):
Bookshelf spring catalogue
Forty titles from independent publishers.
-v / --verbose does the opposite and raises the root logger to DEBUG (a -j -v run on manuscript.docx printed
43 DEBUG lines on standard error).
Source: Apache Tika 4.1.x, Tika-App Integration Testing (its known issue "INFO message on every default-config command") and Apache Log4j 2, Configuration.
The real --help output of 4.1.0
This is the complete, unedited --help output of the 4.1.0 distribution (it goes to standard output and the command
exits with status 0). It is the reference for the rest of the page.
java -jar tika-app-4.1.0.jar --help
Output:
usage: java -jar tika-app.jar [option...] [file...]
Options:
-? or --help Print this usage message
-v or --verbose Print debug level messages
-V or --version Print the Apache Tika version number
-g or --gui Start the Apache Tika GUI
--config=<tika-config.json>
TikaConfig file (JSON as of Tika 4.x). Must be specified before -g or -f !
--convert-config-xml-to-json=<input.xml>
Convert a legacy 3.x XML config to 4.x JSON format (parsers section only),
writing the JSON to stdout. Redirect to save, e.g.:
--convert-config-xml-to-json=tika-config.xml > tika-config.json
-x or --xml Output XHTML content
-h or --html Output HTML content
-t or --text Output plain text content (body)
--md Output Markdown content (body) (default)
-T or --text-main Output plain text content (main content only via boilerpipe handler)
-A or --text-all Output all text content
-m or --metadata Output only metadata
-j or --json Output metadata in JSON
-y or --xmp Output metadata in XMP
-J or --jsonRecursive Output metadata and content from all
embedded files (choose content type
with -x, -h, -t or -m; default is --md)
-a or --async Run Tika in async mode: -a -c <tika-config.json> [-p <pluginsDir>]
-l or --language Output only language
-d or --detect Detect document type
--digest=X Include digest X (md2, md5, sha1,
sha256, sha384, sha512)
--encoding=X Use output encoding X
--password=X Use document password X
-z or --extract Extract all attachements into current directory
--extract-dir=<dir> Specify target directory for -z
--maxEmbeddedDepth=X Maximum depth for embedded document extraction
--maxEmbeddedCount=X Maximum number of embedded documents to extract
-r or --pretty-print For JSON, XML and XHTML outputs, adds newlines and
whitespace, for better readability
Fork Mode (process isolation):
-f or --fork Run parsing in a forked JVM process for isolation
Protects against parser crashes, OOM, and timeouts
--task-timeout=<ms> Total per-file budget in milliseconds
(default: 3600000)
--progress-timeout=<ms> Stall detector: max time with no progress
(default: 120000)
--fork-jvm-args=<args> JVM args for forked process (comma-separated)
e.g., --fork-jvm-args=-Xmx512m,-Dsome.prop=value
--fork-plugins-dir=<dir> Directory containing plugin zips
--list-parsers
List the available document parsers
--list-parser-names
List parsers as tab-separated class-name<TAB>friendly-name
(friendly names are the kebab-case keys used in JSON config)
--list-parser-details
List the available document parsers and their supported mime types
--list-parser-details-apt
List the available document parsers and their supported mime types in apt format.
--list-parser-details-adoc
Same, in AsciiDoc; regenerates docs/modules/ROOT/partials/supported-formats.adoc
--list-detectors
List the available document detectors
--list-detector-names
List detectors as tab-separated class-name<TAB>friendly-name
--list-met-models
List the available metadata models, and their supported keys
--list-supported-types
List all known media types and related information
--compare-file-magic=<dir>
Compares Tika's known media types to the File(1) tool's magic directory
Description:
Apache Tika will parse the file(s) specified on the
command line and output the extracted text content
or metadata to standard output.
Instead of a file name you can also specify the URL
of a document to be parsed.
If no file name or URL is specified (or the special
name "-" is used), then the standard input stream
is parsed. If no arguments were given and no input
data is available, the GUI is started instead.
- GUI mode
Use the "--gui" (or "-g") option to start the
Apache Tika GUI. You can drag and drop files from
a normal file explorer to the GUI window to extract
text content and metadata from the files.
- Tika Pipes mode
For processing many documents from a directory, S3, GCS, Azure, JDBC, etc.
Simplest invocation is two directories as args with no other args:
java -jar tika-app.jar <inputDirectory> <outputDirectory>
Tika Pipes Options:
-i, --inputDir=<dir> Input directory
-o, --outputDir=<dir> Output directory
-n, --numClients Number of forked processes
--Xmx=<size> -Xmx for the forked processes, e.g. --Xmx=1g
-T, --timeoutMillis Timeout for each parse in milliseconds
-c, --config=<file> Tika config file (--config=<file> also accepted)
-p, --pluginsDir Plugins directory
--fileList File list (one path per line, relative to --inputDir or absolute)
--handler Handler type: t=text, h=html, x=xml, m=markdown, b=body, i=ignore (default: m)
--concatenate Concatenate content from all embedded documents
--content-only Output only extracted content (no JSON wrapper); implies --concatenate
--on-exists Behavior when an output file exists: exception (default), replace, skip
-Z Recursively unpack all the attachments, too
--unpack-format=<format> Output format: REGULAR (default) or FRICTIONLESS
--unpack-mode=<mode> Output mode: ZIPPED (default) or DIRECTORY;
DIRECTORY when --unpack-format=FRICTIONLESS and no mode is given
--unpack-include-metadata Metadata for every extracted file. A Frictionless package
carries metadata.json by default; this adds per-file
sidecars to REGULAR zip output
Three things in this text need reading with care, and the official page says so too:
-
-Thas two meanings. In standard mode it is--text-main. In pipes mode it is--timeoutMillis.-cand-pexist only in pipes mode; in standard mode the configuration is--config=<file>. -
-zand--extractare listed with the standard options but switch to pipes mode. Their description ("into current directory") is the 3.x wording; in 4.1.0 they always run through Tika Pipes (see Unpacking attachments). -
The pipes section is a summary. The pipes-mode options are parsed by
TikaAsyncCLIwith Apache Commons CLI, so--handler tand--handler=tboth work, and--fileListtakes a value.
Source: the command above, run on the 4.1.0 distribution, and Apache Tika 4.1.x, Tika Command Line Interface.
Standard mode
In standard mode TikaCLI processes its arguments left to right. An option changes the state (the output type, the
configuration, the password), and a file name, a URL or - parses that input with the current state and writes the
result to standard output. Several inputs in one command are parsed one after the other and their outputs are
concatenated.
The order matters in two ways. An option placed after the file name does not apply to it, and --config= must come
before the first input (and before -g or -f, as the help says), because the configuration is loaded when the first
input is parsed:
tika -d manuscript.docx -t novel.epub # -d applies to the first file, -t to the second
tika novel.epub -t # -t comes too late: the default Markdown is printed
Output:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
Chapter one
It begins at dusk.
# Chapter one
It begins at dusk.
Long options take two dashes and short options are one letter. In 4.1.0 an unknown option fails fast with exit status 1 and a hint, instead of being taken as a URL:
tika -input catalogue.pdf
Output (standard error, stack trace omitted):
Exception in thread "main" java.lang.IllegalArgumentException: Unknown option '-input'. Long-form flags require two dashes (try '--input' instead of '-input'). Run with --help for the full option list.
A missing file is still reported in an unhelpful way, because a name that is not an existing file is tried as a URL. The official integration-test page lists this as a known issue:
Exception in thread "main" java.net.MalformedURLException: no protocol: missing.pdf
Source: Apache Tika 4.1.x, Tika Command Line Interface, Standard-mode Options and Apache Tika 4.1.x, Tika-App Integration Testing.
Help, version and configuration options
| Option | Effect in 4.1.0 |
|---|---|
|
Prints the usage above. If it appears anywhere on the command line, nothing else runs. |
|
Prints |
|
Raises the Log4j root level to |
|
Loads this JSON configuration with |
|
Converts the |
With --config=, the parse uses your configuration instead of the convenience defaults. The Bookshelf desk keeps one
tika-config.json for the intake service and for its batch runs:
{
// Bookshelf intake: shared by the desk CLI and the batch runs
"parsers": [
{ "pdf-parser": { "sortByPosition": true, "extractInlineImages": false } },
{ "default-parser": { "exclude": ["executable-parser"] } }
],
"metadata-filters": [
{ "include-field-metadata-filter": {
"include": ["Content-Type", "dc:title", "dc:creator", "tk:content"] } }
],
"parse-context": {
"embedded-limits": { "maxDepth": 5, "maxCount": 200 },
"timeout-limits": { "totalTaskTimeoutMillis": 120000, "progressTimeoutMillis": 30000 }
},
"pipes": {
"numClients": 2,
"forkedJvmArgs": ["-Xmx768m"]
}
}
tika --config=tika-config.json -j -r manuscript.docx
Output:
{
"Content-Length" : "1418",
"Content-Type" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"dc:creator" : "Ana Torres",
"dc:title" : "The Lighthouse Keeper",
"tk:content-type-magic-detected" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"tk:parsed-by" : [ "org.apache.tika.parser.CompositeParser", "org.apache.tika.parser.DefaultParser", "org.apache.tika.parser.microsoft.ooxml.OOXMLParser", "org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor" ],
"tk:parsed-by-full-set" : [ "org.apache.tika.parser.CompositeParser", "org.apache.tika.parser.DefaultParser", "org.apache.tika.parser.microsoft.ooxml.OOXMLParser" ],
"tk:resource-name" : "manuscript.docx",
"zip:detector-zip-file-opened" : "true"
}
The configuration was applied (DefaultParser now appears in tk:parsed-by, because the parsers list is no longer
the convenience one), but the include-field-metadata-filter was not applied to this standard-mode -j output: all
the keys are printed. The same file in pipes mode, shown later, does apply the filter. This was observed with 4.1.0 and
is not described in the docs, so do not rely on metadata filters when you only use standard mode; check the output of
your own version.
Output formats
One option chooses what is written for each input. The last one given before the input wins.
| Option | Output | Handler behind it |
|---|---|---|
|
Markdown of the body. New in 4.x as the default (3.x defaulted to XHTML). |
|
|
Plain text of the body. |
|
|
The full XHTML document, including |
XML serializer |
|
The same events serialized as HTML. |
HTML serializer with |
|
Plain text of the main content only, boilerplate (navigation, footers) removed. |
Boilerpipe handler |
|
All text, including the |
Text over the whole document |
|
Metadata only, one |
None (content ignored) |
|
Metadata only, as one JSON object. |
None (content ignored) |
|
Metadata only, as an XMP packet. |
None (content ignored) |
|
A JSON array: the container and every embedded document, each with its metadata and a |
|
|
Indents JSON, XML and XHTML output. |
Modifier |
|
Writes the output in charset X instead of UTF-8. It does not change how the input is decoded. |
Modifier |
Markdown and plain text of the Bookshelf manuscript:
tika manuscript.docx
tika -t manuscript.docx
Output:
The Lighthouse Keeper
Chapter one begins at dusk.
The Lighthouse Keeper
Chapter one begins at dusk.
XHTML with pretty printing. The <head> carries the metadata; this output is the SAX event stream of the parse, which
the Content Handlers & Output Formats page explains:
tika -x -r manuscript.docx
Output (blank lines that the pretty printer inserts between elements removed):
<?xml version="1.0" encoding="UTF-8"?><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="tk:content-type-magic-detected" content="application/vnd.openxmlformats-officedocument.wordprocessingml.document"/>
<meta name="dc:title" content="The Lighthouse Keeper"/>
<meta name="dc:creator" content="Ana Torres"/>
<meta name="tk:resource-name" content="manuscript.docx"/>
<meta name="zip:detector-zip-file-opened" content="true"/>
<meta name="Content-Length" content="1418"/>
<meta name="tk:parsed-by" content="org.apache.tika.parser.CompositeParser"/>
<meta name="tk:parsed-by" content="org.apache.tika.parser.microsoft.ooxml.OOXMLParser"/>
<meta name="tk:parsed-by" content="org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor"/>
<meta name="Content-Type" content="application/vnd.openxmlformats-officedocument.wordprocessingml.document"/>
<title>The Lighthouse Keeper</title>
</head>
<body>
<p>The Lighthouse Keeper</p>
<p>Chapter one begins at dusk.</p>
</body>
</html>
-T and -A on the Spanish review page. -T keeps the heading and the first paragraph that boilerpipe judges to be the
article; -A prints everything, including the title and the blank lines of the head:
tika -T reviews-es.html
Output:
Reseñas de lectoresReseñas de lectores
El guardián del faro es una novela pausada y luminosa. Ana Torres construye un mundo pequeño, casi doméstico, donde cada noche el protagonista cuenta las olas y espera una carta que nunca llega.
Note the joined title and heading in the first line and the missing second paragraph: main-content extraction is a
heuristic for article-like web pages, not a general text extractor. Use -t or --md for documents.
XMP output of the manuscript:
tika -y manuscript.docx
Output:
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 6.1.11">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
dc:format="application/vnd.openxmlformats-officedocument.wordprocessingml.document">
<dc:creator>
<rdf:Seq>
<rdf:li>Ana Torres</rdf:li>
</rdf:Seq>
</dc:creator>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">The Lighthouse Keeper</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
--encoding only changes the output charset. The windows-1252 catalogue is decoded correctly either way (Tika detects
its encoding); printed as ISO-8859-1 on a UTF-8 terminal, the accented letters show as replacement characters and the
euro sign, which ISO-8859-1 cannot represent, becomes ?:
tika -t legacy-catalogue.txt
tika --encoding=ISO-8859-1 -t legacy-catalogue.txt
Output:
Catálogo de primavera: novelas de editoriales independientes. Precio 12€. Disponible en tienda y por correo electrónico a la dirección de la librería.
Cat�logo de primavera: novelas de editoriales independientes. Precio 12?. Disponible en tienda y por correo electr�nico a la direcci�n de la librer�a.
--encoding is for consumers that need a specific output charset, not a way to fix the input decoding. Input encoding
is covered on the Character Encoding Detection page.
Metadata: -m, -j and -J
-m prints the metadata sorted by key. The Bookshelf catalogue PDF:
tika -m catalogue.pdf
Output:
Content-Length: 785
Content-Type: application/pdf
access-permission:assemble-document: true
access-permission:can-modify: true
access-permission:can-print: true
access-permission:can-print-faithful: true
access-permission:extract-content: true
access-permission:extract-for-accessibility: true
access-permission:fill-in-form: true
access-permission:modify-annotations: true
dc:creator: Bookshelf Press
dc:format: application/pdf; version=1.4
dc:title: Spring catalogue
pdf:chars-per-page: 67
pdf:contains-damaged-font: false
pdf:contains-non-embedded-font: true
pdf:docinfo:creator: Bookshelf Press
pdf:docinfo:producer: hand-made
pdf:docinfo:title: Spring catalogue
pdf:encrypted: false
pdf:eof-offsets: 785
pdf:has-collection: false
pdf:has-marked-content: false
pdf:has-xfa: false
pdf:has-xmp: false
pdf:incremental-update-count: 0
pdf:num-3d-annotations: 0
pdf:ocr-page-count: 0
pdf:overall-percentage-unmapped-unicode-chars: 0.0
pdf:pdf-version: 1.4
pdf:producer: hand-made
pdf:total-unmapped-unicode-chars: 0
pdf:unmapped-unicode-chars-per-page: 0
tk:content-type-magic-detected: application/pdf
tk:parsed-by: org.apache.tika.parser.CompositeParser
tk:parsed-by: org.apache.tika.parser.pdf.PDFParser
tk:parsed-by-full-set: org.apache.tika.parser.CompositeParser
tk:parsed-by-full-set: org.apache.tika.parser.pdf.PDFParser
tk:resource-name: catalogue.pdf
tk:version-count: 0
xmpTPg:NPages: 1
The 4.x key names (tk:parsed-by, tk:resource-name, kebab-case pdf: keys) are the ones the
Metadata page maps to their 3.x names. Scripts written against 3.x output
(X-Parsed-By, resourceName, pdf:PDFVersion) need updating.
-j prints the same metadata as one JSON object (compact unless -r is given; multi-valued keys become arrays).
-J is the recursive form: a JSON array with one object per document, container first, each with its content in
tk:content. On the publisher’s e-mail it lists the e-mail, the zip it carries, the three files in the zip and the image
inside the Word file. jq keeps the output readable:
tika -J -t publisher-email.eml \
| jq -r '.[] | [."tk:embedded-depth" // "0", ."tk:embedded-resource-path" // "(container)", ."Content-Type"] | @tsv'
Output:
0 (container) message/rfc822
3 /samples.zip/chapter-one.docx/figure1.png image/png
2 /samples.zip/chapter-one.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
2 /samples.zip/catalogue.pdf application/pdf
2 /samples.zip/cover-note.txt text/plain; charset=windows-1252
1 /samples.zip application/zip
The children are listed depth first, and a parent is written after its children (the container is moved to the front).
The container object also carries tk:content-handler-type (TEXT here), tk:parse-time-millis and
tk:parsed-by-full-set, which lists every parser used anywhere in the tree. --maxEmbeddedDepth=1 stops the recursion
after the first level:
tika --maxEmbeddedDepth=1 -J -t publisher-email.eml | jq -r '.[] | ."tk:embedded-resource-path" // "(container)"'
Output:
(container)
/samples.zip
--maxEmbeddedCount=N caps the number of embedded documents in the same way. Both are unlimited by default, set an
EmbeddedLimits in the ParseContext, and correspond to parse-context.embedded-limits in tika-config.json. The
model behind -J (the "list of metadata" of RecursiveParserWrapper, the same JSON as tika-server’s /rmeta) is
described on the Embedded Documents & Recursive Parsing page.
Detection, language and digests
-d runs only the detector and prints the media type. It reads the bytes, so a renamed file is reported as what it is:
tika -d manuscript.docx novel.epub renamed-invoice.png book-cover.jpg
Output:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/epub+zip
application/pdf
image/jpeg
renamed-invoice.png is a PDF, and Tika says so. That is the check the intake desk runs before it trusts a file
extension (the Media Types & Detection page explains the magic,
glob and container steps behind it).
-l parses the text and prints only the detected language. tika-app 4.1.0 bundles the CharSoup detector
(tika-langdetect-charsoup), which reports ISO 639-3 codes as they are (tika-server /language converts them to
two-letter codes, see Tika Server (REST API)):
tika -l reviews-es.html
tika -l reseñas-fr.txt
Output:
spa
fra
These are three-letter codes, not the two-letter es and fr that the 2.x and 3.x Optimaize detector usually returned. Map them
before comparing with stored values. The Language Detection & Translation
page covers CharSoup and the short-text pitfalls.
--digest=X adds a digest of the input bytes to the metadata. The accepted values are md2, md5, sha1, sha256,
sha384 and sha512 (case-insensitive). It uses the Commons Codec digester, which has no SHA-3; for SHA3-256 and the
other SHA-3 variants, configure the Bouncy Castle digester in tika-config.json instead. The digest is a metadata key,
so combine it with -j, -m or -J:
tika -j --digest=sha256 catalogue.pdf | jq -r '."tk:digest:SHA-256"'
shasum -a 256 catalogue.pdf
Output:
775dabd42ebe9c7c1ea7cc6c3164a41fcafc51d3541db835f34d1e9a21135385
775dabd42ebe9c7c1ea7cc6c3164a41fcafc51d3541db835f34d1e9a21135385 catalogue.pdf
The key is tk:digest:SHA-256 in 4.x (X-TIKA:digest:SHA256 in 3.x). The intake desk stores it to spot duplicate
submissions.
Passwords
--password=X supplies a password for encrypted PDF and Office files. Without it, the members-only catalogue fails with
exit status 1:
tika -t members-only.pdf
Output (standard error, stack traces omitted):
Exception in thread "main" org.apache.tika.exception.EncryptedDocumentException: Unable to process: document is encrypted
Caused by: org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException: Cannot decrypt PDF, the password is incorrect
A password on the command line is visible to other users of the machine (in ps output and the shell history). The
4.1.0 source also reads the environment variable TIKA_PASSWORD as the default password, which keeps it off the command
line. TIKA_PASSWORD is not mentioned in --help or on the CLI page; it was found in the TikaCLI source and tested:
# MEMBERS_PDF_PASSWORD holds the sample file's test password; in real use fill it from a secret store
export TIKA_PASSWORD="$MEMBERS_PDF_PASSWORD"
tika -t members-only.pdf
Output:
Bookshelf spring catalogue
Forty titles from independent publishers.
--password=X on the command line overrides the environment variable. The password applies to every encrypted document
of the run, including embedded ones; for per-file passwords write a PasswordProvider in Java (see
Parser API & AutoDetectParser).
Source: Apache Tika 4.1.x, Tika Command Line Interface
and the 4.1.0 TikaCLI source
(the TIKA_PASSWORD default).
Standard input and URLs
With - or no input, and data waiting on standard input, tika-app parses standard input. With a name that is not an
existing file it tries a URL, so file:, http: and https: URLs work:
cat catalogue.pdf | tika -t
cat renamed-invoice.png | tika -d
tika -d "file://$PWD/novel.epub"
Output:
Bookshelf spring catalogue
Forty titles from independent publishers.
application/pdf
application/epub+zip
Standard input has no file name, so detection relies on the bytes alone, which is enough for the renamed PDF. For text formats that need a name hint, pass a file instead. Fetching a URL makes the CLI an HTTP client: run it only on URLs you trust, never on URLs taken from an untrusted document or request (the Security page explains the server-side request forgery risk).
Source: the Description section of --help above.
Listing parsers, detectors and media types
The listing options print what the distribution contains, then exit. They are the quickest way to find the
friendly name a component has in tika-config.json.
| Option | Output (4.1.0) |
|---|---|
|
The parser tree, starting at |
|
|
|
Each parser with the media types it supports. |
|
The same in Maven APT format. |
|
The same in AsciiDoc. Used to regenerate the official supported-formats page. |
|
The detector tree under |
|
|
|
Meant to list the metadata models and their keys. On 4.1.0 it printed a single line, |
|
Every known media type with its aliases, supertype and parser (3756 lines). |
|
Compares Tika’s media types with the magic directory of the |
tika --list-parser-names | grep -E 'pdf|ooxml|csv'
tika --list-detector-names
tika --list-supported-types | grep -A3 '^application/pdf$'
Output:
org.apache.tika.parser.csv.TextAndCSVParser text-and-csv-parser
org.apache.tika.parser.microsoft.ooxml.OOXMLParser ooxml-parser
org.apache.tika.parser.microsoft.ooxml.xwpf.ml2006.Word2006MLParser word-2006-ml-parser
org.apache.tika.parser.pdf.PDFParser pdf-parser
org.apache.tika.detect.apple.BPListDetector bp-list-detector
org.apache.tika.detect.gzip.GZipSpecializationDetector gzip-specialization-detector
org.apache.tika.detect.image.RawTiffDetector raw-tiff-detector
org.apache.tika.detect.microsoft.POIFSContainerDetector poifs-container-detector
org.apache.tika.detect.mkv.MatroskaDetector matroska-detector
org.apache.tika.detect.ogg.OggDetector ogg-detector
org.apache.tika.detect.ole.MiscOLEDetector misc-ole-detector
org.apache.tika.detect.zip.DefaultZipContainerDetector default-zip-container-detector
application/pdf
alias: application/x-pdf
supertype: application/octet-stream
parser: org.apache.tika.parser.pdf.PDFParser
The lists reflect the machine, not only the jars. On the host used for this page Tesseract was not installed, so
TesseractOCRParser (present in lib/tika-parser-ocr-module-4.1.0.jar) did not appear in --list-parsers, and the
startup log said "text recognizers: none found among the loaded parsers". Install Tesseract, as the
OCR with Tesseract page describes, and the parser appears.
The GUI
-g / --gui opens org.apache.tika.gui.TikaGUI, a Swing window, and so does running the jar with no arguments and
nothing on standard input (double-clicking the jar on a desktop does that). It is the tool the Tika in Action book
introduces in chapter 2, and it has changed little since: you drop a file on the window, or use File > Open… or
File > Open URL…, and the View menu switches between six views of the same parse.
| View menu item | What it shows |
|---|---|
Metadata |
The metadata, as with |
Formatted text |
The XHTML rendered as HTML, as with |
Plain text |
The body text, as with |
Main content |
The boilerpipe main content, as with |
Structured text |
The XHTML source, as with |
Recursive JSON |
The list of metadata of the container and its embedded documents, as with |
--config= placed before -g is passed to the GUI, so you can inspect a file with the production configuration:
tika --config=tika-config.json --gui
The GUI parses in its own JVM, with no fork, so a hostile file can hang or crash the window, and it needs a desktop
session (on a server without a display, Swing cannot open the window; this was not tested here). The GUI was not opened for this page;
the menu items above were read from the 4.1.0 TikaGUI source.
Source: Apache Tika 4.1.x, Tika Command Line Interface,
the 4.1.0 TikaGUI source
and Tika in Action, chapter 2.
Fork mode
-f / --fork keeps the standard-mode command line but runs the parse in a separate JVM through PipesForkParser, the
4.x replacement of the removed ForkParser. If the parser crashes the JVM, runs out of memory or hangs, the forked JVM
dies or is killed and the CLI reports it instead of dying itself. That is the right way to look at a file you do not
trust, such as an attachment that has already crashed a worker.
| Option | Default | Meaning |
|---|---|---|
|
off |
Parse in a forked JVM. |
|
3600000 (1 hour) |
Total budget per file. The fork is killed when it runs out. Same default as |
|
120000 (2 minutes) |
Stall detector: the fork is killed as hung if it makes no progress for this long. |
|
none (heap auto-sized) |
Comma-separated JVM arguments for the fork, for example |
|
the distribution’s |
Directory with plugin zips for the fork. |
|
removed |
Removed in 4.0. Using it is an error that names the two replacements. |
tika -f -t catalogue.pdf
Output (the 35 empty lines before the title are shortened to one):
Spring catalogue
Bookshelf spring catalogue
Forty titles from independent publishers.
The run took about 12.7 seconds of wall time against 6.3 seconds without -f, because a second JVM starts and loads the
parsers again. The log on standard error shows the fork being sized and started:
INFO [main] 22:53:22,064 org.apache.tika.pipes.core.PipesParser Using per-client server mode with 1 clients
INFO [main] 22:53:22,066 org.apache.tika.pipes.core.PerClientServerManager pipes-cpu-sizing: hostCores=8, numClients=1, parentReserved=2, autoCap=slice=6, heap=MaxRAMPercentage=60
INFO [main] 22:53:23,030 [fork] pipesClientId=0 org.apache.tika.pipes.core.server.PipesServer forked JVM max heap: 14752 MB
INFO [main] 22:53:28,472 org.apache.tika.pipes.core.PipesClient clientId=0: server successfully started
Without --fork-jvm-args, the fork’s heap is auto-sized to 60 % of the machine’s memory (MaxRAMPercentage=60); on a
shared machine set an explicit -Xmx. The sizing rules are on the official "Forked-JVM CPU and Heap Sizing" page.
Fork mode is not a drop-in copy of standard mode in 4.1.0. Reading the source and running it showed these differences:
-
The output comes from a
PipesForkParserresult inCONCATENATEparse mode (orRMETAwith-J), so-tuses the full text handler: the title from the<head>appears, with the blank lines, as above. -
-Tmaps to theBODYhandler, not to boilerpipe.-A,-d,-land-ymap to theIGNOREhandler and print nothing useful; use them without-f. -
--password=andTIKA_PASSWORDwere not passed to the fork:-f --password=reader-pw -t members-only.pdfprinted nothing, and-f -jshowedtk:exception:container-exceptionwith the "password is incorrect" error. The parse inside the fork also used its own defaults rather than the parsers of--config=, as far as the source shows (the fork configuration is built from the timeouts, JVM arguments, plugin directory and embedded limits only). -
The result metadata includes
tk:source-pathwith the absolute path of the input andtk:content-handler-type.
So use fork mode for what it is for (looking safely at one dangerous file) and pipes mode for batches. For production
isolation inside a service, use PipesForkParser from Java (see Tika Pipes)
or tika-server, whose parsing endpoints always fork.
Source: Apache Tika 4.1.x, Tika Command Line Interface, Fork Mode,
Apache Tika 4.1.x, Pipes, Timeouts,
Apache Tika 4.1.x, Forked-JVM CPU and Heap Sizing and the
4.1.0 TikaCLI source (processWithFork).
Tika Pipes mode
Pipes mode is the batch mode of 4.x. It replaces the 1.x to 3.x tika-batch mode of tika-app (-bc, -numConsumers,
-maxRestarts and the rest), which was removed with the tika-batch module. tika-app hands the arguments to the
tika-async-cli module (TikaAsyncCLI), which writes a temporary tika-config.json from a template, merges your
--config into it, applies the command-line overrides and runs an AsyncProcessor: a file-system pipes iterator lists
the input files, a pool of forked JVMs parses them, and a file-system emitter writes one output file per input. The
Tika Pipes page explains those roles; this section covers the command line.
How pipes mode is activated
tika-app 4.1.0 enters pipes mode when any of these holds (checked before anything else, except --help):
-
exactly two arguments and the first is an existing directory (
tika in/ out/); -
the last two arguments are an existing directory followed by a directory or a path that does not exist yet, with options in front;
-
a single argument ending in
.json, which is read as a complete pipes configuration; -
any of
-i,--inputDir(in fact any argument starting with--input),-o,--outputDir(any argument starting with--output),--fileList,-z,-Z,--extract,--extract-dir,-aor--async.
When it switches, it prints a one-line banner on standard error, so you can tell which path ran:
tika-app: running in Tika Pipes mode (async dispatch via -a/--async); use --help for options.
Source: Apache Tika 4.1.x, Tika Command Line Interface, How Pipes mode is activated
and the 4.1.0 TikaCLI.testForAsync source.
The simplest run: two directories
The Bookshelf intake folder holds six of the sample files. Two directory arguments and nothing else parse them all:
ls intake
tika intake out
ls out
Output (standard error shortened to the banner, the sizing line and the summary):
catalogue.pdf legacy-catalogue.txt manuscript.docx novel.epub publisher-email.eml renamed-invoice.png
tika-app: running in Tika Pipes mode (async dispatch via -a/--async); use --help for options.
INFO [main] 22:54:40,643 org.apache.tika.pipes.core.PerClientServerManager pipes-cpu-sizing: hostCores=8, numClients=1, parentReserved=2, autoCap=slice=6, heap=user-set in forkedJvmArgs
INFO [main] 22:54:47,270 tika.pipes Successfully finished processing 6 files in 6653 ms
catalogue.pdf.json legacy-catalogue.txt.json manuscript.docx.json novel.epub.json publisher-email.eml.json renamed-invoice.png.json
Each output file is the RMETA list of metadata (the -J format) of one input, with Markdown content. For the
manuscript:
jq . out/manuscript.docx.json
Output:
[
{
"tk:source-path": "manuscript.docx",
"tk:content-type-parser-override": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"dc:creator": "Ana Torres",
"tk:resource-name": "manuscript.docx",
"tk:content": "The Lighthouse Keeper \n\nThe Lighthouse Keeper\n\nChapter one begins at dusk.\n",
"tk:parsed-by": [
"org.apache.tika.parser.CompositeParser",
"org.apache.tika.parser.microsoft.ooxml.OOXMLParser",
"org.apache.tika.parser.microsoft.ooxml.xwpf.XWPFEventBasedWordExtractor"
],
"tk:content-type-magic-detected": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"dc:title": "The Lighthouse Keeper",
"tk:parse-time-millis": "3",
"tk:parsed-by-full-set": [
"org.apache.tika.parser.CompositeParser",
"org.apache.tika.parser.microsoft.ooxml.OOXMLParser"
],
"zip:detector-zip-file-opened": "true",
"tk:embedded-depth": "0",
"Content-Length": "1418",
"tk:content-handler-type": "MARKDOWN",
"Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
]
tk:source-path is the path relative to the input directory, which keeps the output portable. publisher-email.eml.json
holds six objects (the e-mail and its five embedded documents), as with -J. The renamed PDF’s file is
renamed-invoice.png.json with "Content-Type": "application/pdf" inside: the output name follows the input name, the
content follows the bytes.
The output directory mirrors the input tree (subdirectories included) and the file name is the input name plus .json.
Pipes-mode options
| Option | Default | Meaning |
|---|---|---|
|
none |
Input directory; a single file also works (its parent becomes the base path). The long form is |
|
|
Output directory. The long form is |
|
none |
Text file with one path per line, relative to |
|
|
Content handler: |
|
off |
Parse mode |
|
off |
Parse mode |
|
|
What to do when an output file exists: |
|
2 (1 in the bare two-directory form) |
Number of forked JVMs that parse in parallel. A |
|
unset: heap auto-sized ( |
|
|
config or library default (30000 in the bare form) |
Total task timeout per input. Sets |
|
the built-in template |
A |
|
the distribution’s |
Where the pipes plugins (fetchers, emitters, iterators) are loaded from. |
|
n/a |
Forces pipes mode. Redundant with any of the triggers above. |
|
off |
Unpacking, see Unpacking attachments. |
The bare-form defaults (one client, -Xmx1g, a 30-second task timeout) were read from the 4.1.0 TikaAsyncCLI
source; the numClients=1 in the sizing line above confirms the client count. The other defaults are from the official CLI page
and were confirmed by the runs below.
|
Some older notes list an |
Source: Apache Tika 4.1.x, Tika Command Line Interface, Tika Pipes Processing
and the 4.1.0 source of TikaAsyncCLI
and PluginsWriter.
Text for the search index: --handler and --content-only
The intake service feeds plain text to its search index. Two workers with 512 MB each and a one-minute budget per file:
tika -i intake -o text-out --handler t --content-only -n 2 --Xmx=512m -T 60000
ls text-out
Output (standard error shortened):
INFO [main] 22:54:59,271 org.apache.tika.pipes.core.async.AsyncProcessor Using per-client server mode with 2 workers
INFO [main] 22:54:59,274 org.apache.tika.pipes.core.PerClientServerManager pipes-cpu-sizing: hostCores=8, numClients=2, parentReserved=2, autoCap=slice=3, heap=user-set in forkedJvmArgs
INFO [main] 22:55:06,956 tika.pipes Successfully finished processing 6 files in 7729 ms
catalogue.pdf.txt legacy-catalogue.txt.txt manuscript.docx.txt novel.epub.txt publisher-email.eml.txt renamed-invoice.png.txt
Each file holds only the text. The text handler includes the <head> title, so each file starts with blank lines and the
title; for the manuscript, after 14 empty lines:
The Lighthouse Keeper
The Lighthouse Keeper
Chapter one begins at dusk.
--handler b (body) leaves out the head, and --handler m (the default) gives Markdown, which most chunkers for search
and RAG handle better. --concatenate without --content-only keeps the metadata and puts all the embedded text into
the container’s tk:content, a good shape for "one search document per submission".
Re-runs, --on-exists and the exit status
Run the same command again and every emit fails, because the output files exist and the default is exception:
tika -i intake -o text-out --handler t --content-only
echo "exit status: $?"
Output (standard error, one of six messages shown, stack traces and paths shortened):
WARN [pool-2-thread-1] 22:55:20,790 [fork] pipesClientId=0 org.apache.tika.pipes.core.server.EmitHandler emit exception
java.io.IOException: Output already exists (onExists=EXCEPTION, not overwritten): .../text-out/manuscript.docx.txt. Use an empty output dir, delete the file, or set onExists to REPLACE or SKIP.
INFO [main] 22:55:22,047 tika.pipes Successfully finished processing 6 files in 9213 ms
exit status: 0
Two lessons. First, choose the policy: --on-exists skip resumes an interrupted batch (only missing outputs are
written), --on-exists replace reprocesses everything. Second, the exit status is 0 and the summary says
"Successfully finished" even though nothing was written. In pipes mode a per-file failure (a parse exception, a
timeout, a crash of a fork, an emit failure) is recorded for that file and the batch continues; the command only fails
for configuration and startup errors. A script must check the outputs, the log, or a configured reporter (the
file-system-jsonl-reporter writes one status line per file), not just $?.
This run also shows that -n defaults to 2 outside the bare form: the warnings came from pipesClientId=0 and
pipesClientId=1 without any -n.
A file list and a configuration file
--fileList processes only the listed files, which suits a "reprocess these two" request from the editors:
printf 'manuscript.docx\nnovel.epub\n' > batch.txt
tika -i intake --fileList batch.txt -o listed --handler t
ls listed
Output:
manuscript.docx.json novel.epub.json
-c (or --config=) merges the Bookshelf tika-config.json shown earlier into the pipes template. Its pipes
section sets two clients and -Xmx768m; the --Xmx=1g on the command line replaces the -Xmx and keeps the rest:
tika -i intake -o cfg-out -c tika-config.json --Xmx=1g
jq . cfg-out/manuscript.docx.json
Output (standard error shortened):
INFO [main] 22:57:03,054 org.apache.tika.pipes.core.async.AsyncProcessor Using per-client server mode with 2 workers
INFO [main] 22:57:10,207 tika.pipes Successfully finished processing 6 files in 7193 ms
[
{
"dc:title": "The Lighthouse Keeper",
"dc:creator": "Ana Torres",
"tk:content": "The Lighthouse Keeper \n\nThe Lighthouse Keeper\n\nChapter one begins at dusk.\n",
"Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
]
Here the include-field-metadata-filter of the file was applied: only the four listed keys remain. The merge is
shallow, so a parsers section in your file replaces the template’s parsers list as a whole (including its
convenience settings for PDF and Office), and a fetchers or emitters section replaces the template’s file-system
ones. -i and -o are applied after the merge, to every file-system-fetcher, file-system-pipes-iterator and
file-system-emitter, whatever their ids.
Defaults of pipes mode
The template that pipes mode starts from (config-template.json in tika-async-cli-4.1.0.jar) is worth knowing,
because everything you do not override comes from it:
{
"content-handler-factory": {
"basic-content-handler-factory": { "type": "TEXT", "writeLimit": -1, "throwOnWriteLimitReached": true }
},
"parsers": [
{ "default-parser": {} },
{ "pdf-parser": { "extractActions": true, "extractInlineImages": true,
"extractIncrementalUpdateInfo": true, "parseIncrementalUpdates": true } },
{ "ooxml-parser": { "includeDeletedContent": true, "includeMoveFromContent": true, "extractMacros": true } },
{ "office-parser": { "extractMacros": true } }
],
"fetchers": { "fsf": { "file-system-fetcher": { "basePath": "FETCHER_BASE_PATH", "extractFileSystemMetadata": false } } },
"emitters": { "fse": { "file-system-emitter": { "basePath": "EMITTER_BASE_PATH", "fileExtension": "json", "onExists": "EXCEPTION" } } },
"pipes-iterator": { "file-system-pipes-iterator": { "basePath": "FETCHER_BASE_PATH", "countTotal": true, "fetcherId": "fsf", "emitterId": "fse" } },
"pipes": { "parseMode": "RMETA" },
"plugin-roots": "PLUGIN_ROOTS"
}
(The JSON was reformatted to fit; the placeholders are replaced at run time by the -i, -o and plugin paths.) The
TEXT handler type is overridden per file by --handler, whose default is Markdown. There is no write limit
(writeLimit: -1) and the convenience PDF and Office settings are on. For a production batch, pass your own
configuration with an output-limits section and the limits of the
Robustness, Limits & Timeouts page.
Source: the config-template.json resource of the 4.1.0 tika-async-cli jar in the distribution’s lib/ directory.
A complete pipes configuration as the only argument
A single .json argument runs the pipeline it describes. This is how the Bookshelf nightly job is defined, with
named fetcher and emitter ids and absolute paths:
{
"fetchers": {
"intake": { "file-system-fetcher": { "basePath": "/srv/bookshelf/intake" } }
},
"emitters": {
"extracted": { "file-system-emitter": {
"basePath": "/srv/bookshelf/extracted", "fileExtension": "json", "onExists": "REPLACE" } }
},
"pipes-iterator": {
"file-system-pipes-iterator": {
"basePath": "/srv/bookshelf/intake", "fetcherId": "intake", "emitterId": "extracted" }
},
"pipes": { "numClients": 2, "parseMode": "RMETA", "forkedJvmArgs": ["-Xmx768m"] },
"parse-context": {
"timeout-limits": { "totalTaskTimeoutMillis": 120000, "progressTimeoutMillis": 30000 }
},
"plugin-roots": "/opt/tika-app-4.1.0/plugins"
}
tika bookshelf-nightly.json
Output (standard error shortened):
tika-app: running in Tika Pipes mode (async dispatch via -a/--async); use --help for options.
INFO [main] 22:57:20,432 org.apache.tika.pipes.core.async.AsyncProcessor Using per-client server mode with 2 workers
INFO [pool-2-thread-3] 22:57:26,121 org.apache.tika.pipes.core.PipesClient clientId=1: server successfully started
INFO [pool-2-thread-2] 22:57:26,121 org.apache.tika.pipes.core.PipesClient clientId=0: server successfully started
INFO [main] 22:57:27,558 tika.pipes Successfully finished processing 6 files in 7153 ms
In this form nothing is merged and no template applies: the file must name a pipes-iterator, and plugin-roots is
required. Without it the run stops with TikaConfigException: plugin-roots must be specified. The paths are
shown as /srv/bookshelf/.... Replacing the file-system
fetcher with S3, GCS, Azure Blob or JDBC (after adding their plugin zips to plugins/) uses the same command, which is
what the help means by "S3, GCS, Azure, JDBC, etc."; those plugins were not run for this page.
Unpacking attachments
-z and -Z write the embedded files' bytes, not their text. Both run in pipes mode (parse mode UNPACK) and accept a
directory or a single file. -Z extracts recursively; -z is documented as "direct attachments (depth 1)" and is
implemented as an embedded depth limit of 2.
| Option | Meaning |
|---|---|
|
Extract direct attachments. |
|
Extract all attachments recursively. |
|
Output directory for the bytes; the same as |
|
|
|
|
|
Metadata for every extracted file: a Frictionless package carries |
The publisher’s e-mail, recursively:
mkdir mail && cp intake/publisher-email.eml mail/
tika -Z -i mail -o unpacked
find unpacked -type f | sort
Output:
unpacked/publisher-email.eml-embed/00000001.zip
unpacked/publisher-email.eml-embed/00000002.docx
unpacked/publisher-email.eml-embed/00000003.png
unpacked/publisher-email.eml-embed/00000004.pdf
unpacked/publisher-email.eml-embed/00000005.bin
unpacked/publisher-email.eml.json
The files are named <input>-embed/<8-digit id>.<suffix>, with the suffix chosen from the detected type, and the
.json next to them is the usual list of metadata that maps each id to its original name. 00000001.zip is
samples.zip itself, and 00000005.bin is notes/cover-note.txt, a windows-1252 text file that received .bin in
this run. Read the names from the metadata, not from the suffixes. The CLI keeps this naming whatever
unpack-config your --config sets for suffixStrategy, zeroPadName, embeddedIdPrefix or keyBaseStrategy; the
other unpack-config settings apply, and "includeOriginal": true there is the only way to also copy the source
document into the output.
-z with a single file. The options go before the file: --extract-dir is rewritten to -o, and Commons CLI stops
reading options at the first positional argument, so tika -z mail/publisher-email.eml --extract-dir=shallow fails with
TikaConfigException: Can't have more than 2 unknown args.
tika -z --extract-dir=shallow mail/publisher-email.eml
find shallow -type f | sort
Output:
shallow/publisher-email.eml-embed/00000001.zip
shallow/publisher-email.eml-embed/00000002.docx
shallow/publisher-email.eml-embed/00000003.pdf
shallow/publisher-email.eml-embed/00000004.bin
shallow/publisher-email.eml.json
In 4.1.0, -z on the e-mail wrote the zip and the three files inside it, and left out only the image inside the Word
file. The zip’s entries are one level deeper than "direct attachments of the e-mail", so the depth accounting counts
differently from what the description suggests. Check with your own files when the depth matters, or set
parse-context.embedded-limits.maxDepth explicitly.
A Frictionless Data Package of the same e-mail:
tika -Z --unpack-format=FRICTIONLESS -i mail -o fl
find fl -type f | sort
jq '.resources[] | {path, mediatype, name}' fl/publisher-email.eml/datapackage.json
Output:
fl/publisher-email.eml.json
fl/publisher-email.eml/datapackage.json
fl/publisher-email.eml/metadata.json
fl/publisher-email.eml/unpacked/00000001.zip
fl/publisher-email.eml/unpacked/00000002.docx
fl/publisher-email.eml/unpacked/00000003.png
fl/publisher-email.eml/unpacked/00000004.pdf
fl/publisher-email.eml/unpacked/00000005.bin
{ "path": "unpacked/00000003.png", "mediatype": "image/png", "name": "figure1.png" }
{ "path": "unpacked/00000002.docx", "mediatype": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "name": "chapter-one.docx" }
{ "path": "unpacked/00000004.pdf", "mediatype": "application/pdf", "name": "catalogue.pdf" }
{ "path": "unpacked/00000005.bin", "mediatype": "text/plain", "name": "notes/cover-note.txt" }
{ "path": "unpacked/00000001.zip", "mediatype": "application/zip", "name": "samples.zip" }
Each resource in datapackage.json also has bytes and a hash (sha256:...), so a consumer can verify what it
reads. The name is the original name from the e-mail or the archive; it is untrusted input. Never use it as a path
on disk without sanitizing it (a name such as ../../etc/cron.d/x is a classic "zip slip"). The 8-digit file names
Tika writes are safe; that is one reason it writes them. The official home page says the Frictionless format is planned
to become the default in 4.2.0.
Removed and changed options
The command line changed more between 3.x and 4.x than in any earlier release. 4.1.0 rejects the removed options with an error (exit status 1) instead of misreading them.
| Old option | Removed in | What to use / what 4.1.0 does |
|---|---|---|
|
2.0 (3.x printed an error naming the wiki page) |
Run tika-server (see Tika Server (REST API)). 4.1.0: |
|
4.0 |
Call tika-server over HTTP. The official page explains that it sent raw sockets, including a bare |
|
4.0 |
|
|
4.0 |
|
Batch mode ( |
4.0, with tika-batch |
Pipes mode: |
|
4.0 |
|
|
4.0 (format) |
|
|
4.0 |
Not implemented in 4.x (commented out in the source, listed as a known issue on the integration-test page). Keep your |
|
earlier |
Accepted and ignored: container-aware detection is always on. |
|
4.0 |
The default is |
|
4.0 |
|
|
4.0 |
|
The removed options, run on 4.1.0 (standard error, stack traces omitted):
tika --server
tika --client=http://localhost:9998
tika -eUTF-8 -t catalogue.pdf
tika --fork-timeout=1000 -f catalogue.pdf
Output:
Exception in thread "main" java.lang.IllegalArgumentException: Unknown option '--server'. Run with --help for the full option list.
Exception in thread "main" java.lang.IllegalArgumentException: Unknown option '--client=http://localhost:9998'. Run with --help for the full option list.
Exception in thread "main" java.lang.IllegalArgumentException: Unknown option '-eUTF-8'. Long-form flags require two dashes (try '--eUTF-8' instead of '-eUTF-8'). Run with --help for the full option list.
Exception in thread "main" java.lang.IllegalArgumentException: --fork-timeout was removed in 4.0 because its meaning was ambiguous (total budget vs. stall detector). Use --task-timeout=<ms> for the total per-file budget and/or --progress-timeout=<ms> for the stall detector instead.
(The two-dash suggestion for -eUTF-8 is the generic hint; the right replacement is --encoding=UTF-8.)
Source: Apache Tika 4.1.x, Tika Command Line Interface,
Apache Tika 4.1.x, Migrating to Tika 4.x and
the TikaCLI source at the 3.3.2
and 4.1.0 tags.
From the book to 4.x
Tika in Action (chapter 2) introduced tika-app as a single runnable jar of Tika 1.0 with three uses: a command-line
extractor, the GUI and a simple socket server (--server). The changes since then, in short:
| Topic | 1.x (book) | 2.x | 3.x | 4.x |
|---|---|---|---|---|
Distribution |
One fat jar |
One fat jar |
One fat jar |
Zip: thin jar, |
Java |
as stated in the book (Tika 1.0 era); 8 by 1.28 |
8 |
11 |
17 |
Default output |
XHTML ( |
XHTML |
XHTML ( |
Markdown ( |
Configuration |
|
XML |
XML |
JSON ( |
Server |
|
removed (error) |
removed (error) |
removed (unknown option) |
Network client |
|
kept |
kept |
removed |
Inline |
yes |
yes |
yes |
removed |
Batch |
tika-batch ( |
tika-batch, |
tika-batch, |
Tika Pipes mode only |
Fork mode |
|
|
|
|
Metadata keys |
1.x names |
|
|
|
Language detection |
n-gram profiles, 2-letter codes |
Optimaize |
Optimaize |
CharSoup, ISO 639-3 codes |
The version cells for 1.x and 2.x were taken from the --help source at the 1.28.5 and 2.9.4 tags and from the
Introduction & Architecture page; none of those versions
was run for this page.
Source: Tika in Action, chapter 2 (written for Tika 1.0), Apache Tika 3.3.2, Getting Started and Apache Tika 4.1.x, Migration to 4.x.
When to use tika-app, and when not
| Task | Use |
|---|---|
Look at one file: its type, its metadata, its text |
Standard mode. |
Look at one file that may be hostile |
Fork mode |
Check what your service will see |
Standard mode with |
Find a component’s JSON name |
|
Convert a 3.x XML configuration |
|
Process a folder once, or a nightly batch |
Pipes mode, with a configuration file and a reporter. |
Parse on request from an application |
Not tika-app: use tika-server, tika-grpc, or |
Run Tika in containers |
The |
Memory, performance and robustness
-
JVM start-up dominates. Every standard-mode call starts a JVM and loads more than a hundred parsers: about 6 seconds for a tiny PDF here. Put several files in one call (
tika -t a.pdf b.docx) or use pipes mode, which starts its forks once and reuses them. -
Standard mode has no isolation. A parser bug, a zip bomb or an endless loop affects the CLI JVM itself. Set
-Xmxbefore-jar, use-ffor unknown files, and do not run standard mode on untrusted input in a loop. -
Fork and pipes heap. Without
--Xmx/--fork-jvm-args, each fork’s heap is sized from the machine’s memory (60 % in the fork-mode run above). With-n 4on a shared host, set--Xmxso thatntimes the heap plus the parent fits. -
Timeouts. Fork mode:
--task-timeoutand--progress-timeout. Pipes mode:-Tfor the total budget, andprogressTimeoutMillisin the configuration for the stall detector. -
Limits. The CLI defaults do not cap the output size (
writeLimit: -1in the pipes template, and unlimited embedded depth and count). Addoutput-limitsandembedded-limitsto your configuration, as described on the Robustness, Limits & Timeouts page. -
Temporary files. Spooling and per-fork temp directories go to
java.io.tmpdir(logged at start-up); point it at a volume with enough space for large batches with-Djava.io.tmpdir=...before-jarand in--fork-jvm-args.
Pitfalls and security
-
Pinning. The CLI is in flux for 4.x. Pin the version (
tika-app-4.1.0) in scripts and re-read--helpwhen you upgrade. -
Exit status in pipes mode. 0 even when every file failed; check outputs or a reporter.
-
Option order.
--config=before the first file; pipes options before a positional input. -
-Tand-cmean different things in the two modes. -
Convenience defaults. Standard mode and the pipes template turn on macro extraction, deleted Word text, PDF actions and incremental updates. That is right for inspection and forensics; for a public index, deleted text and macros may be content you do not want to publish. Use your own configuration.
-
Passwords on the command line are visible in process lists and shell history; prefer
TIKA_PASSWORDfrom a secret store, and remember that fork mode did not pass it in 4.1.0. -
URLs. Passing a URL makes tika-app fetch it. Do not build tika-app command lines from untrusted strings, and quote file names (a file named
-inputis taken as an option unless it exists). -
Extracted names are untrusted. Original names in
-Joutput anddatapackage.jsoncome from the documents. -
Hostile files. The CLI parses with the same parsers as the library and has the same exposure to parser vulnerabilities (for example CVE-2025-54988 / CVE-2025-66516 in the PDF module before 3.2.2). Keep the distribution current; the Security page covers the threat model.
Source: Apache Tika 4.1.x, Security and Apache Tika, Security.
What was verified and what was not
Verified by running the official 4.1.0 zip distribution on Java 25 (macOS): the --help and --version output, every
standard-mode output format shown, -d, -l, --digest, --password and TIKA_PASSWORD, standard input and
file: URLs, the listing options, --maxEmbeddedDepth, fork mode (including the password and handler differences),
the removed-option errors, pipes mode with two directories, -i / -o with --handler, --content-only, -n,
--Xmx, -T, --fileList, -c, --on-exists (default and skip), a single .json pipes configuration (with and
without plugin-roots), and -z, -Z and --unpack-format=FRICTIONLESS.
Read from the 4.1.0 source but not exercised: the bare-form timeout (30 s) and heap (-Xmx1g), --unpack-mode,
--unpack-include-metadata, --compare-file-magic, --list-parser-details-apt and -adoc, --fork-plugins-dir,
--progress-timeout and --task-timeout actually killing a fork, the GUI and its menus, and pipes plugins other than
the file system. Not checked at all: Windows behavior, and the 1.x / 2.x command lines (read from source only).