(back to ao3-ing) | (cross-indexed under charts & tables)

advanced ao3 filtering: lesson ii

the ao3 search queries i found digging through the site's source code

written 1 september 2023.

(click here to skip straight to the table) / (click here to only skip my preamble of context)

so, as some of you May Or May Not Be Aware, i enjoy a very high level of ao3 filter literacy, which allows me to perform just The Most Specific search requests / create the most potent autofilter cocktail you've ever seen in your life.

however, as is human nature, i am not simply content to know how to automatically filter out mere tags in my sticky filters; no— i wish to also automatically filter my search results based off numerous other requests like word count, language, crossovers, and more, and i don't want to use the ao3 savior extension because i want the search results number to reflect the exact number of fics i have to look through and not merely hide things with css!!

now, i'm sure we're all familiar with the sexy times w/wangxian incident, wherein some dick made a work with a wall of tags so long and irrelevant, it resulted in sitewide tag limits on works, and i'm sure many of us are familiar with the otp:true search within results input, which will return fics with Exactly One relationship tagged.

one of the caveats of otp:true is that— say you're looking for fics about characters X and Y, and don't much care whether it's platonic or romantic as long as it's Strictly About Them. one of the caveats of otp:true is that if you go directly to the X/Y or X & Y tags on AO3 and put otp:true into the search within results box, it will also get rid of all fics tagged with as X/Y and X & Y and nothing else.

i'm also the type of person who really enjoys reading about well-developed side pairings in my fanfics. from my own experiences, they don't seem to be particularly common in genshin (or any weeb fandoms i've joined that born after the weeb migration to ao3, really), but a lot of people have a bad habit of overtagging their fics, so otp:true will also get rid of fics where X/Y is the main pairing with a couple (or a lot.) of side ships going on.

basically, using otp:true can often result in throwing a lot of baby out with the bathwater!

so in the wake of the sexy times w/wangxian incident giving us a limit of how many tags we can apply to a work, i concluded that there must be a way for ao3 to determine how many tags a work had applied to it. therefore, i reasoned, because otp:true can count how many relationship tags are applied to a work, there must be a way to filter works based off the number of tags it has!

after a lot of dead ends messing with the search w/in results box (which very frequently resulted in that one page that said "hey you're making too many requests at once we're putting you in ao3 search jail"), i just kind of gave up trying to figure out a query phrasing and went to look at the ao3 source code to see if i could figure out how otp:true itself worked, since it obviously wasn't something that existed in the vanilla apache lucene search parser that ao3 uses for its queries.

anyway, i was very unfamiliar with github at that time and struggled to find even which part of the repository i should be looking in to have even a shot at finding what i wanted, so i gave up after a couple of hours.

i tried again a couple times afterwards, even downloading the entire repository at one point, and eventually i did find where in the code otp:true was defined, as well as where in the code the parser was told how to parse otp:true/false correctly, so i tried a bunch of queries using stuff i saw in there (without really understanding what was going on lol), none of which returned what i wanted.

anyway so basically my current understanding is, "we have the groundwork in place on ao3 to allow people to search for fics based on the number of relationships tagged in a fic, but it hasn't currently been added to the index of things we can sort fics by". which sucks, bc i'd like to filter out works with more than, like, mmmm i guess six or seven relationship tags, just so that i can crush those last few untagged chatfics that will occasionally show up in my results (not so much anymore, since i filtered out some relationships i don't really care about but are really common in chatfics), but it is what it is for now!!!

ANYWAY, all this just to say that i've dug through the ao3 source code again recently and come up with a table of non-tag-filter requests you can use in the "search within results" box that i have personally tested and verified to work!

before i jump into it, though, there's something i want to quickly explain: basically, there are four types of inputs for these parameters: integers, strings, dates, and booleans.

integers just means "whole numbers", for those of you who weren't that into math.
string refers to, like, a string of text. like, pretend each word is a bead and you are threading them all along a string. the ao3 query parser (and most coding languages/spreadsheet software) require uncurled quotation marks ("these") around multiple words to recognize the words as one string. [1]
dates must be formatted as yyyy-mm-dd.
boolean means "TRUE" or "FALSE".

all input types except for booleans will also accept ranges, logical operators like AND/&&, OR/||, NOT/!, and requests grouped with parentheses.

ranges will use square brackets [] to denote ranges that include the number written and curly brackets {} to denote ranges that exclude the number written. these can be mixed and matched. to "TO" between endpoints MUST be in all-caps.


a lot of these examples are going to be really strangely specific, mostly to give people an idea of how to really creatively mix and match queries for optimal specificity and nuance. if you want normal examples, read this old admin post.

query input type brief explanation example
word_count integer filters for word count -word_count:[* TO 1000} will will return fics that are 1,000 words or longer.
major_version integer about as close as we can get to a "current number of chapters" filter currently. it is very imperfect. major_version:5 will mostly[2] return fics with 5 chapters currently.
minor_version integer the number of times a work has been edited slightly[3]. minor_version:[10 TO 50] will return fics which have been tweaked 10-50 times.
it is a not very useful filter, in my opinion.
expected_number_­of_chapters integer the total number of chapters a work has or is expected to have. expected_number_of_chapters:([5 TO 20] !(7 || 13)) will return fics that expect to have anywhere from 5–20 chapters, unless they expect to have 7 or 13 chapters.
language_id string[4] filters for work language. language_id:en will return all fics which have english listed as their language.
fandom_ids integer works the same as filter_ids, but will only apply to tags in the fandom category. -fandom_ids:>66432169 -fandom_ids:<30845288 -fandom_ids:{30845288 TO 66432169} will filter out every single fandom except for honkai impact 3rd and honkai: star rail.
character_ids integer works the same as filter_ids, but will apply only to tags in the character category. character_ids:* will return all fics which have at least one character tagged.
relation­ship_ids integer works the same as filter_ids, but will only apply to tags in the relationships category. -relationship_ids:* will return all fics without any relationships tagged.
collection_ids integer filters for works in collections based on the collection's ID number[5]. collection_ids:1 will return works that were written for yuletide
user_ids integer filters based off the ID number(s) of its creator(s)[6]. user_ids:8 will return all works written by ao3 founder astolat.
work_skin_id integer filters for works based off their workskin ID number[5]. work_skin_id:* will return all works which have a work skin. since there are only three public workskins, and many people don't utilize the work skins they may not realize they have applied, it is not a very useful filter.
complete boolean filters works based on completion status. complete:true will return all fics that are complete.
crossover boolean filters works based on whether or not they are crossovers. crossover:false will return all works whose tagged fandom(s) have been designated as "related" by tag wranglers. mind the dependence on wranglers here.
otp boolean filters works based on whether or not they only have one relationship tagged. otp:true will return works with either only one relationship tag, or whose relationship tags are all synonyms.
backdate boolean filters for works which have been backdated. backdate:true will return all works which have had their posting dates altered.
restricted boolean filters for works which have been archive-locked. restricted:false will return all works which are available without an AO3 account.
in_anon_­collection boolean filters for works whose creators are anonymous. in_anon_collection:true will return all works which belong to a collection that makes its works anonymous.
nonfiction boolean filters for nonfiction works. nonfiction:true will return all works which are tagged with things like "nonfiction", "essay", "reviews", "reference", etc.
hits integer filters works based on how many hits it has. hits:<420 will return all fics with fewer than 420 hits.
comments_count integer filters works based on how many comments it has. comments_count:0 will return all works without comments. go make someone's day.
kudos_count integer filters works based off how many kudos it has. kudos_count:68 will return all works with exactly 68 kudos. go make someone's day (2).
bookmarks_count integer filters works based on how many bookmarks it has. bookmarks_count:[0 TO 25] will return all works with 0–25 bookmarks.
title string filters works based on their titles title:[bird TO bite] will return all works with "bird", "bite", or any words between them alphabetically in its title.
summary string filters works based on their summaries. summary:f*ck will return all works which have a word that starts with "f" and ends with "ck", like "firetruck" :).
notes string filters works based off the text in its author's notes notes:(tw || (tw? !two)) will return all works which have "tw" or a three-letter word that starts with "tw" (other than "two") somewhere in its notes.
endnotes string filters works based off the text contained in the work's end notes. -endnotes:(twitter || tiktok || "tik tok") will return all works without the words "twitter", "tiktok", or "tik tok" in their end notes.
tag string filters works based off the text of its tags (not neces­sarily the tag itself!) tag:kink will return all works which the author tagged as containing some kind of kink. or belongs to a kinkmeme idk.
creators string functions similarly to user_ids, except working with strings rather than ID numbers. creators:"the lady of shalott" will return all works written under the pseud "the lady of shalott".
series.title string filters works by their series title series.title:* will return all works which are part of a series. mind the period between "series" and "title".
created_at date filters works based on the date they were created. created_at:2022-01-01 will return all works created[7] on 1 january 2022.
updated_at date filters works based on the date they were last updated. updated_at:[2022-01-01 TO 2023-01-01} will return all works which were last updated in 2022.
revised_at date filters works based on their date of last revision. revised_at:2020-09-28 will return all works which were last revised (including first published / last updated, assuming no revisions were made since then) on 28 september 2020.
imported_­from_url string filters works based on where they were imported from. probably designed with an ao3 that Didn't become The place to post fics in mind lol. imported_from_url:*dreamwidth* will return all fics which were imported from dreamwidth. you can't use "https://" at the front, so that should be replaced with an asterisk (*).
work_types string [8] filters works based on what type of medium it is. work_types:Art will return all works with some sort of art / image embedded in it, assuming the author tagged for it.
sort string sorts works based on words, hits, kudos, comments, and bookmarks. sort:posted will sort the works by their posting dates, from newest to oldest. to invert the order of any parameter used for sort, add > for sort:>[parameter].

mix and match

lol jk this page is long enough; i think it's best if i make the mix and match examples its own page (if i get around to it at all).

just know that you can mix and match all these search queries in ways that'll blow your tits or dicks or anything in-between clean off!!!!!!! like -relationship_ids:>55891266 -relationship_ids:<55414227 -relationship_ids:{55414227 TO 55891266} relationship_ids:* sort:>posted language_id:en -expected_number_of_chapters:1 word_count:[1000 TO *} for all english multichapter xv works over 1k words that are tagged as with only xv, whether that be romantic only, platonic only, or both at once w/o any other relationships, sorted by their posting date ascending!!

or -(filter_ids:103132 AND complete:false AND word_count:[* TO 10000}) -(filter_ids:103132 AND complete:true AND word_count:[* TO 50000}) to filter out slow burns if they are incomplete AND less than 10k words or complete AND less than 50k words within the same query!!!!!

the world is your oyster, my good dudes!!!!

:YunJinWink:

Footnotes:

[1] — curly quotation marks (“these”) are encoded separately from the uncurled ones, and ao3 has problems working with them. (it's also the reason why you need to make sure you're working with uncurled quotation marks when linking to images/other sites when using html on ao3!!)
return

[2] — i haven't yet really looked into how major_version is defined in the ao3 source code, but my current guess is that a work's major version goes up when a chapter is added, deleted, or drafted.
return

[3] — you know how when you look into your ao3 history, you'll sometimes see "minor edits made since then" beside the last visited date? i think whatever gets that to show up, like changing tags, correcting typos, etc., increases a work's minor_version count.
return

[4] — rather than any old string, the language_id uses those two-letter language codes. also, unlike other queries which end in _id, language is one of the only two without an 's' at the end, the other being work skins.
return

[5] — as far as i can tell, there is no way to find a this type of ID number from the frontend website aside from testing out ranges of numbers, which is how i found the ID number of the anon collection i use: 584.
return collections | return workskins

[6] — if a work is in an anonymous collection, then this filter will not apply to it.
return

[7] — because backdating is a thing that exists, the dates you see in the corner when using this filter might not be the same as the date(s) you input into the search box. use in conjunction with backdate:true to avoid this.
return

[8] — although technically a string, you only have four options here: "Audio", "Art", "Video", and "Text", although "Text" is not particularly useful since it makes up the vast majority of works on ao3 LOL. these strings are also cAsE sEnSiTiVe!!!
return

(back to ao3-ing) | (cross-indexed under charts & tables)