The BibTeX citations keys generated by the standard Zotero exporters are always generated at time of export, using an algorithm that usually generates unique keys. For serious LaTeX users, “usually” presents the following problems:
For a LaTeX author, the citation keys have their own meaning, fully separate from the other reference data, even if people usually pick a naming scheme related to them. As the citation key is the piece of data that connects your bibliography, this is a piece of data you want to have control over. BBT offers you this control:
You can also
By default, BBT generates the citation key from the item information, and this key may change when you edit the item. Such keys are called
dynamic keys, which are marked with an asterisk (
*) in the reference list view, and are displayed in italics in the item details.
You can fix the citation key (called
pinning in BBT) for an item by adding the text
Citation Key: [your citekey] anywhere in the
extra field of the reference on a line of its own. You can generate a pinned citation key by selecting one or more items, right-clicking, and selecting
Generate BibTeX key, which will add the current citation key to the
extra field, thereby pinning it. These keys are shown without the asterisk (
*) marker in the middle column, and non-italicized in the details view, to distinguish them from dynamic keys.
You can drag and drop citations into your LaTeX/Markdown/Orgmode editor, and it will add a proper
cite command is
configurable for LaTeX by setting the config option in the preferences. Do not include the leading backslash.
This feature requires a one-time setup: choose the Quick Copy format under the
Citation keys preferences for BBT, and go to Zotero preferences, tab Export, under Default Output Format, select “Better BibTeX Quick Copy: [format you just selected]”.
The plugin will generate BibTeX comments to show whether a key conflicts and with which entry. BBT integrates with Zotero: Report Customizer to display the BibTeX key plus any conflicts between them in the zotero report.
BBT also implements a new citekey generator for those entries that don’t have one set explicitly; the formatter pattern language mostly follows the JabRef key formatting syntax in the Better BibTeX preferences (you can get there via the Zotero preferences, or by clicking the Better BibTeX “Preferences” button in the addons pane.
The default key pattern is
[auth:lower][shorttitle3_3][year] ; if you have papers that use keys which were generated by the key generator of the standard Bib(La)TeX exporters of Zotero you may want to use
[zotero:clean] instead in order to ease migration from existing exports for people who previously used the standard Zotero Bib(La)TeX exports. You will be offered this choice on first run of BBT.
A common pattern is
[auth:lower][year], which means
note that changing the pattern used to cause all your non-pinned keys to be regenerated in Zotero 4. In Zotero 5, this is no longer the case; changing a pattern will only affect references being created/changed after you changed the pattern. If you want your keys to update after a pattern change you will have to select your references, right-click, and select
Refresh. This will not affect keys you have pinned.
If you want to get fancy, you can set multiple patterns separated by a vertical bar, of which the first will be applied that yields a non-empty string. If all return a empty string, a random key will be generated.
An example application for this behavior is to use the
tex.shortauthor from the extra field when defined to generate short citation keys for entries with long group author names, but to default to
[Extra:transliterate:replace=(?\:tex\\.shortauthor\[\:\=\]\\s+(\\w+))|.*,$1,regex:clean:lower][>0][year] | [auth:lower][year]
although this particular case can be handled more succinctly with
[extra=tex.shortauthor:transliterate:clean:lower][>0][year] | [auth:lower][year]
note the non-greedy regex pattern before the non-capturing group. Using this pattern, a reference of the “American Psychological Association” from 2021 and
tex.shortauthor: APA in the extra field would get the citekey
apa2021. Without the definition in the extra field the generated citekey would be
To generate your citekeys, you use a pattern composed of functions and filters. Broadly, functions grab text from your item, and filters transform that text. The full list of functions and filters is:
+<joinchar>: The last name of the first two authors, and “.ea” if there are more than two.
+<joinchar>: The last name of the first author, and the last name of the second author if there are two authors or “.etal” if there are more than two.
+<joinchar>: The last name of the first author, and the last name of the second author if there are two authors or “EtAl” if there are more than two. This is similar to
auth.etal. The difference is that the authors are not separated by “.” and in case of more than 2 authors “EtAl” instead of “.etal” is appended.
edtrForeIni: The forename initial of the first author.
+<joinchar>: The beginning of each author’s last name, using no more than
+<joinchar>: The first
N(default: all) characters of the
Mth (default: first) author’s last name.
+<joinchar>: The first 5 characters of the first author’s last name, and the last name initials of the remaining authors.
edtrorLastForeIni: The forename initial of the last author.
+<joinchar>: The last name of the last author
+<joinchar>: Corresponds to the BibTeX style “alpha”. One author: First three letters of the last name. Two to four authors: First letters of last names concatenated. More than four authors: First letters of last names of first three authors concatenated. “+” at the end.
+<joinchar>: The last name of up to N authors. If there are more authors, “EtAl” is appended.
+<joinchar>: The last name if one author is given; the first character of up to three authors' last names if more than one author is given. A plus character is added, if there are more than three authors.
date: The date of the publication
extra: A pseudo-field from the extra field. eg if you have
Original date: 1970in your
extrafield, you can get it as
tex.shortauthor: APAwhich you could get with
tex.field will be picked up, the other fields can be selected from this list of key names.
firstpage: The number of the first page of the publication (Caution: this will return the lowest number found in the pages field, since BibTeX allows
inspire-hep: Fetches the key from inspire-hep based on DOI or arXiv ID
journal: returns the journal abbreviation, or, if not found, the journal title, If ‘automatic journal abbreviation’ is enabled in the BBT settings, it will use the same abbreviation filter Zotero uses in the wordprocessor integration. You might want to use the
abbrfilter on this.
keywordN: Tag number
language: Tests whether the entry has the given language set, and skips to the next pattern if not
lastpage: The number of the last page of the publication (See the remark on
library: returns the name of the shared group library, or nothing if the reference is in your personal library
month: the month of the publication
origdate: the original date of the publication
origyear: the original year of the publication
shorttitleN_M: The first
N(default: 3) words of the title, apply capitalization to first
M(default: 0) of those
shortyear: The last 2 digits of the publication year
title: Capitalize all the significant words of the title, and concatenate them. For example,
An awesome paper on JabRefwill become
veryshorttitleN_M: The first
N(default: 1) words of the title, apply capitalization to first
M(default: 0) of those
year: The year of the publication
zotero: Generates citation keys as the stock Zotero Bib(La)TeX export does. Note that this pattern inherits all the problems of the original Zotero citekey generation – you should really only use this if you have existing papers that rely on this behavior.
postfix+1=<spec>: a pseudo-function that sets the citekey disambiguation postfix using an sprintf-js format spec for when a key is generated that already exists. Does not add any text to the citekey otherwise. You must include exactly one of the placeholders
%(a)s(alpha, lowercase) or
%(A)s(alpha, uppercase). For the rest of the disambiguator you can use things like padding and extra text as sprintf-js allows. With
+1the disambiguator is always included, even if there is no need for it because no duplicates exist. The default format is
0: an alias for
[postfix=-%(n)s]. Emulates the disambiguator of the standard Zotero exports. When you use
[zotero]in your pattern,
>X: a pseudo-function which aborts the current pattern generation if what came before it is
Xcharacters or less (
[>0]is a typical use. You would typically use this with something like
[auth][>0][year] | [title][year]which means if there's no author you get
title-yearrather than just
=typeName: a pseudo-function that aborts the current pattern generation if the Zotero reference type does not equal
typeName. You can test for multiple typenames at once by separating them with slashes (
[=journalArticle/report]). Valid typeNames are:
auth... functions will fall back to editors if no authors are present on the item.
Note: the functions above all have the
clean filter (see below) automatically applied to them. If you want more control,
edtr, … and all the author-related fields that mimic the JabRef equivalents also have capitalized versions (so
Edtr, …) which follow the same algorithm but do not have any cleaning (diacritic folding, space removal, stripping of invalid citekey characters) applied. These can be used to pass through the filters specified below much like the fields from the table above. See also “usage note” below. For all the non-author fields, you can use the unprocessed reference fields directly:
(fields marked JM are only available in Juris-M).
+initialsadds initials to any author name function. Specify using e.g.
abbr: Abbreviates the text. Only the first character and subsequent characters following white space will be included.
alphanum: clears out everything but unicode alphanumeric characters (unicode character classes
ascii: removes all non-ascii characters
capitalize: uppercases the first letter of each word
clean=allow_spaces? (boolean): transliterates the citation key and removes unsafe characters
condense=sep? (string): this replaces spaces in the value passed in. You can specify what to replace it with by adding it as a parameter, e.g
condense=_will replace spaces with underscores. Parameters should not contain spaces unless you want the spaces in the value passed in to be replaced with those spaces in the parameter
default=text (string): Returns the given text if no output was generated
discard: discards the input
eq=n (number): If the length of the output is not equal to the given number, skip to the next pattern. Alias:
fold=mode? (“german” | “japanese” | “chinese”): tries to replace diacritics with ascii look-alikes. Removes non-ascii characters it cannot match
format-date=format? (string): formats date as by replacing y, m and d in the format
ge=n (number): If the length of the output is not greater than or equal to the given number, skip to the next pattern. Alias:
gt=n (number): If the length of the output is not greater than the given number, skip to the next pattern. Alias:
jieba: word segmentation for Chinese references. Uses substantial memory; must be enabled under Preferences -> Better BibTeX -> Advanced -> Citekeys
kuromoji: word segmentation for Japanese references. Uses substantial memory; must be enabled under Preferences -> Better BibTeX -> Advanced -> Citekeys
le=n (number): If the length of the output is not lower than or equal to the given number, skip to the next pattern. Alias:
local-time: transforms date/time to local time. Mainly useful for dateAdded and dateModified as it requires an ISO-formatted input.
longer=n (number): If the length of the output is not longer than the given number, skip to the next pattern. Alias:
lower: Forces the text inserted by the field marker to be in lowercase. For example,
[auth:lower]expands the last name of the first author in lowercase.
lt=n (number): If the length of the output is not less than the given number, skip to the next pattern. Alias:
ne=n (number): If the length of the output is equal to the given number, skip to the next pattern. Alias:
nopunct: Removes punctuation
nopunctordash: Removes punctuation and word-connecting dashes
numeric: returns the value if it’s an integer
postfix=postfix (string): postfixes with its parameter, so
postfix=_will add an underscore to the end if, and only if, the value it is supposed to postfix isn’t empty
prefix=prefix (string): prefixes with its parameter, so
prefix=_will add an underscore to the front if, and only if, the value it is supposed to prefix isn’t empty. If you want to use a reserved character (such as
\), you’ll need to add a backslash (
\) in front of it.
replace=find (string), replace (string), mode? (“string” | “regex”): replaces text, case insensitive;
select=start? (number), n? (number): selects words from the value passed in. The format is
select=1,4would select the first four words. If
numberis not given, all words from
startto the end of the list are selected.
filters out common words like ‘of’, ‘the’, … the list of words can be seen and changed by going into
about:config under the key
extensions.zotero.translators.better-bibtex.skipWords as a comma-separated, case-insensitive list of words.
If you want to strip words like ‘Jr.’ from names, you could use something like
[Auth:nopunct:skipwords:fold] after adding
jr to the skipWords list. Note that this filter is always applied if you use
title (which is different from
split-ideographs: Treat ideaographs as individual words
substring=start? (number), n? (number): (
n(default: all) characters starting at
transliterate=mode? (“minimal” | “german” | “de” | “japanese” | “ja” | “zh” | “chinese”): transliterates the citation key. If you don’t specify a mode, the mode is derived from the item language field
upper: Forces the text inserted by the field marker to be in uppercase. For example,
[auth:upper]expands the last name of the first author in uppercase.
>X: a pseudo-filter which aborts the current pattern generation if what came before it is
Xcharacters or less (
[>0]is a typical use. You would typically use this with something like
[auth][journal:>0][year] | [title][year]which means if there's no journal you get
title-yearrather than just
(x): The string between the parentheses will be inserted if the field marker preceding this modifier resolves to an empty value. The placeholder
xmay be any string. For instance, the marker
[volume:(unknown)]will return the entry's volume if set, and the string
unknownif the entry's volume field is not set.
Usage note: the functions
select rely on whitespaces for word handling. The JabRef functions strip
whitespace and thereby make these filter functions sort of useless. You will in general want to use the fields from the
table above, which give you the values from Zotero without any changes. The fields with
** are only available in Juris-M.