Code for excluding taxon

Hi iNaturalist community. I do not know if this already exists but recently a family member of mine made something he calls a bookmarklet. It is javascript that can be used to make a bookmark that allows you to exclude taxon. For example say you want to ID shorebirds but are bad at identifying gulls you could type gulls and in your iNaturalist it excludes that taxon. Although this can be done by editing the URL this is a quick easy way to add and subtract all kinds of exclusions.

Simply create a new bookmark, give it a title, then where the URL usually goes write javascript: (but do not italicize) then after the colon paste the script. Than go to iNaturalist and see the results. In the photo below I wanted to ID unknowns for the ID-a-Thon but did not want to sift through life. I hope this helps people in there IDing quest. I did not make this, I was given it by someone in my family much better at coding.

Below is the script:

var taxon = prompt(“Enter ONE taxon ID or taxon name to exclude:”); if (taxon != null) { u = new URL(location.href); var taxon_id; if (isNaN(taxon)) { fetch(`https://api.inaturalist.org/v1/taxa/autocomplete?q=${taxon}`).then( (r) => { r.json().then((j) => { if (j.total_results == 0) { alert(‘Bad taxon!’) } else { taxon_id = j.results[0].id; current_without = u.searchParams.get(‘without_taxon_id’); if (current_without == null) { u.searchParams.set(“without_taxon_id”, taxon_id); } else { u.searchParams.set(‘without_taxon_id’, `${current_without},${taxon_id}`); } location.href = u.href; } }); } ); } else { taxon_id = parseInt(taxon); u.searchParams.set(“without_taxon_id”, taxon_id); location.href = u.href; }; }

edit: look below for improved code.

1 Like

the easier way to do this is to use the url modifier in the explore or identify pages&identified=false https://www.inaturalist.org/observations?place_id=1&identified=false

https://www.inaturalist.org/pages/search+urls

Here is the full page of url modifiers, your whole method of scripting and calling from the api is a bit convoluted and redundant

are you actually using this? just looking at the syntax, i don’t see how this could actually work as intended. the single and double quotes are all wrong, and location would generally be a property of window or document. also, the code would just exclude whatever was the first taxon returned from the API, but that wouldn’t necessarily be the taxon you wanted, if more than one was returned.

i suppose it might be faster to click on a button than to type this into the URL. so there might be a legitimate reason for using bookmarklets in some cases.

this would add identified=false to the existing URL:

javascript: (()=>{ let u = new URL(window.location.href); u.searchParams.set("identified", false); window.location.href = u.href; })();

there could be other cases like setting date filters based on current datetime, navigating to related pages, etc.

1 Like

Yes, I actively am using this. Once it is set up it is awesome. I have a bookmarklet in my bookmarks bar. When I am in iNat I click it, type what I do not want in and it work. For example in iNat (regularly) there is an option to search for unknowns, but I did not want this is life, or viruses which also shows up. So I typed life and anything with any kind of ID disappeared. Yes in iNat you could search a specific group, but this allows for easy exclusion of groups while not excluding other things. Like if you wanted to do moths and butterflies but not a certain group. Without editing the URL. I do not know javascript, so I cannot speak to any errors. However I am using it and it works. It also can exclude more than one thing. I know there are plenty of ways to exclude already which I have and do use. This is for specific circumstances, and is mostly intended to help identifiers. Even though the pop-up box says ID or name, I have been informed name probably works better.

Hi. I am the family member that @redeft23 is referring to. You can ask me further questions about the code.

When you mention the single and double quotes, do you mean how I used both? I don’t see how that is an issue aside from inconsistent style. For location, the reason I’m not using window or document is simply because it works without it, but I looked it up and it seems like it is better practice to do what you said.

I am aware that it excludes the first returned taxon, but the alert/prompt interface is kind of limited, unless I use the bookmarklet to edit the HTML and add a <select> or something similar. Do you have any suggestions?

Additionally, it seems like the API usually returns more than one result. Take the results for Black-capped Chickadee, which returns 13 results (mostly subspecies), yet the one that is likely intended is listed first. I think that one of the only times an incorrect result would be chosen by the code is if someone didn’t enter the full name. It should usually work as intended.

This is a good idea and seems like it would be very useful, but maybe not always wanted.

Could you please elaborate on this?

Thanks for your feedback

1 Like

no. look at the original thread. some of the quotes in the code snippet are curly quotes like ‘’ (single) and “” (double). for Javascript, I believe you need to use plain straight quotes like ' (single) or " (double), or else use backticks ` as delimiters.

you could make a selection menu that just pops up in the middle of the screen. or if you want to stick with alerts, you could make present the top 10 options and ask the user to select the option they want by typing 1, 2, 3,…, etc.

maybe, but if it works 70% of the time, that still means that it doesn’t work 30% of the time. there are plenty of cases where different things have the same common name or similar common names, or where different things have the same scientific name (animal vs plant or genus vs section). there are also cases where people might not want to type the whole long name of something. in the standard system, you can also usually just type the first few letters in each word of the name, and that will allow you to find near matches, but the thing you want may not always show up first in the list.

1 Like

I see, yes. They weren’t like that in the original code. It seems like they were converted somehow. I tested it and it seems like when I paste the code into the browser search bar and copy that (which is how I was removing line breaks and tabs for the bookmarklet, then copy that and paste it somewhere, the quotes are made curly. It depends where I paste it though.

I updated the code to use a popup like you suggested (I even styled it to look decent and use iNat’s theme). It currently displays up to the top 20 results, which should be sufficient, but I can always add UI for pagination. It seems to work pretty well and be user-friendly from my basic tests, but you can let me know what you think.

As a side note, is there any scenario where it would be good to display both common and scientific name? I think there was one case where two items in the list had the same (common) name.

Begin edit

I improved the code more after originally posting this reply.

Bookmarklet usage guide:

  1. Click the bookmarklet, which should bring up a popup where your cursor is focused on the search field, so you can start typing right away.
  2. Type a taxon ID, partial/full common or scientific name, and press enter (or click “Search”).
    1. Examples of what you can enter include: 144815, Black-capped Chickadee, Black-capped, Poecile atricapillus, Aves, Birds, Gulls, Mushrooms, Bugs.
      1. iNat’s API works fine with all the above. Inputs like “mushrooms” and “bugs” will have top results of “Fungi Including Lichens” and “Insects” respectively.
  3. Your keyboard will now be focused on the Submit button, so either press enter/click if the name above looks correct, or change it in that above dropdown menu.
  4. You can also hit Cancel to close the menu and cancel it. Additionally, you can change your search query in the search box (just hit “Search”/enter again afterwards).

I implemented a basic check to follow the API rate limit of 60 requests/minute (or 1/sec) that hopefully doesn’t let you spam “Submit.”

Also, I decided to just put all the HTML in a string and append it to the body rather than using document.createElement(), .appendChild(), and setting styles/attributes with JS.

End edit

Here is all the code:

Copy-paste this for the bookmarklet

document.body.insertAdjacentHTML('beforeend', '<div class="bootstrap" style="width: 100%; height: 100%; background-color: rgba(51, 51, 51, 0.553); z-index: 1001; position: fixed; top: 0px; left: 0px;"> <div style="box-sizing: border-box; padding: 2rem; width: 40%; background-color: rgb(238, 238, 238); z-index: 1002; position: fixed; top: 40%; left: 30%; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.176) 0px 6px 12px;display:flex;flex-direction: column;gap:1rem;"> <form id="sans_taxon_search_form" style="flex:1;"> <h2 style="margin-top: 0px; margin-bottom: 1rem;">Exclude Taxon</h2> <input type="search" name="taxon" class="form-control" placeholder="Taxon ID or partial/full name" style="width: 70%;display: inline-block;margin-right:0.35rem;" autocomplete="off"> <input type="submit" name="submit" class="btn btn-default" value="Search"> </form> <form id="sans_taxon_sel_form" style="flex:1;"> <select class="form-control" name="taxon_id"> <option value="" disabled selected>-- Search Something --</option> </select> <button class="btn btn-success" style="margin-top: 0.5rem;" type="submit" name="submit" disabled>Submit</button> <button class="btn btn-default" style="margin-top: 0.5rem; margin-left: 0.35rem" name="cancel">Cancel</button> <p style="margin-top: 0.5rem;"><i>You can exclude multiple taxa by using this bookmarklet again after clicking "Submit"</i></p> </form> </div> </div>'); var srch_form = document.getElementById("sans_taxon_search_form"); var sel_form = document.getElementById("sans_taxon_sel_form"); var last_submitted_time, taxon_id; var btn_submit = sel_form.submit; var btn_cancel = sel_form.cancel; sel_form.addEventListener("submit", function(e) { e.preventDefault(); var taxon_id = e.target.taxon_id.value; var current_without = u.searchParams.get("without_taxon_id"); if (current_without == null) { u.searchParams.set("without_taxon_id", taxon_id); } else { u.searchParams.set("without_taxon_id", `${current_without},${taxon_id}`); } window.location.href = u.href; }); btn_cancel.addEventListener("click", function(e) { sel_form.parentElement.parentElement.remove(); }); srch_form.taxon.focus(); srch_form.addEventListener("submit", function(e) { e.preventDefault(); var time = e.timeStamp; if ((time - (last_submitted_time ?? 0)) >= 1000) { last_submitted_time = time; var form = e.target; var taxon = form.taxon.value; if (taxon != null && taxon.trim() != "") { u = new URL(window.location.href); if (isNaN(taxon)) { fetch(`https://api.inaturalist.org/v1/taxa/autocomplete?q=${taxon}&per_page=20`).then((r) => { r.json().then((j) => { var select = sel_form.taxon_id; if (j.total_results == 0) { select.options[0].innerHTML = "No results"; sel_form.submit.disabled = true; } else { select.innerHTML = ""; for (const result of j.results) { var opt = document.createElement("option"); opt.innerHTML = result.preferred_common_name ?? (`${result.rank} ${result.name}`); opt.value = result.id; select.appendChild(opt); } sel_form.submit.disabled = false; sel_form.submit.focus(); } }); }); } else { taxon_id = parseInt(taxon); var current_without = u.searchParams.get("without_taxon_id"); u.searchParams.set("without_taxon_id", (current_without == null ? "" : `${current_without},`) + taxon_id); window.location.href = u.href; }; } } else { alert("Slow down!"); } });

Readable:

document.body.insertAdjacentHTML('beforeend', '<div class="bootstrap" style="width: 100%; height: 100%; background-color: rgba(51, 51, 51, 0.553); z-index: 1001; position: fixed; top: 0px; left: 0px;"> <div style="box-sizing: border-box; padding: 2rem; width: 40%; background-color: rgb(238, 238, 238); z-index: 1002; position: fixed; top: 40%; left: 30%; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.176) 0px 6px 12px;display:flex;flex-direction: column;gap:1rem;"> <form id="sans_taxon_search_form" style="flex:1;"> <h2 style="margin-top: 0px; margin-bottom: 1rem;">Exclude Taxon</h2> <input type="search" name="taxon" class="form-control" placeholder="Taxon ID or partial/full name" style="width: 70%;display: inline-block;margin-right:0.35rem;" autocomplete="off"> <input type="submit" name="submit" class="btn btn-default" value="Search"> </form> <form id="sans_taxon_sel_form" style="flex:1;"> <select class="form-control" name="taxon_id"> <option value="" disabled selected>-- Search Something --</option> </select> <button class="btn btn-success" style="margin-top: 0.5rem;" type="submit" name="submit" disabled>Submit</button> <button class="btn btn-default" style="margin-top: 0.5rem; margin-left: 0.35rem" name="cancel">Cancel</button> <p style="margin-top: 0.5rem;"><i>You can exclude multiple taxa by using this bookmarklet again after clicking "Submit"</i></p> </form> </div> </div>');

var srch_form = document.getElementById("sans_taxon_search_form");
var sel_form = document.getElementById("sans_taxon_sel_form");
var last_submitted_time, taxon_id;

var btn_submit = sel_form.submit;
var btn_cancel = sel_form.cancel;

sel_form.addEventListener("submit", function(e) {
    e.preventDefault();
    var taxon_id = e.target.taxon_id.value;
    var current_without = u.searchParams.get("without_taxon_id");
    if (current_without == null) {
        u.searchParams.set("without_taxon_id", taxon_id);
    } else {
        u.searchParams.set("without_taxon_id", `${current_without},${taxon_id}`);
    }
    window.location.href = u.href;
});

btn_cancel.addEventListener("click", function(e) {
    sel_form.parentElement.parentElement.remove();
});

srch_form.taxon.focus();

srch_form.addEventListener("submit", function(e) {
    e.preventDefault();
    var time = e.timeStamp;
    if ((time - (last_submitted_time ?? 0)) >= 1000) {
        last_submitted_time = time;

        var form = e.target;
        var taxon = form.taxon.value;

        if (taxon != null && taxon.trim() != "") {
        u = new URL(window.location.href);
        if (isNaN(taxon)) {
            fetch(`https://api.inaturalist.org/v1/taxa/autocomplete?q=${taxon}&per_page=20`).then((r) => {
                r.json().then((j) => {
                    var select = sel_form.taxon_id;
                    if (j.total_results == 0) {
                        select.options[0].innerHTML = "No results";
                        sel_form.submit.disabled = true;
                    } else {
                        select.innerHTML = "";
                        for (const result of j.results) {
                            var opt = document.createElement("option");
                            opt.innerHTML = result.preferred_common_name ?? (`${result.rank} ${result.name}`);
                            opt.value = result.id;
                            select.appendChild(opt);
                        }

                        sel_form.submit.disabled = false;
                        sel_form.submit.focus();
                    }
                });
            });
        } else {
            taxon_id = parseInt(taxon);
            var current_without = u.searchParams.get("without_taxon_id");
            u.searchParams.set("without_taxon_id", (current_without == null ? "" : `${current_without},`) + taxon_id);
            window.location.href = u.href;
        };
    }
    } else {
        alert("Slow down!");
    }
});

HTML:

<div class="bootstrap" style="width: 100%; height: 100%; background-color: rgba(51, 51, 51, 0.553); z-index: 1001; position: fixed; top: 0px; left: 0px;">
    <div style="box-sizing: border-box; padding: 2rem; width: 40%; background-color: rgb(238, 238, 238); z-index: 1002; position: fixed; top: 40%; left: 30%; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.176) 0px 6px 12px;display:flex;flex-direction: column;gap:1rem;">
        <form id="sans_taxon_search_form" style="flex:1;">
            <h2 style="margin-top: 0px; margin-bottom: 1rem;">Exclude Taxon</h2>
            <input type="search" name="taxon" class="form-control" placeholder="Taxon ID or partial/full name" style="width: 70%;display: inline-block;margin-right:0.35rem;" autocomplete="off">
            <input type="submit" name="submit" class="btn btn-default" value="Search">
        </form>
        
        <form id="sans_taxon_sel_form" style="flex:1;">

            <select class="form-control" name="taxon_id">
                <option value="" disabled selected>-- Search Something --</option>
            </select>
            <button class="btn btn-success" style="margin-top: 0.5rem;" type="submit" name="submit" disabled>Submit</button>
            <button class="btn btn-default" style="margin-top: 0.5rem; margin-left: 0.35rem" name="cancel">Cancel</button>
            <p style="margin-top: 0.5rem;"><i>You can exclude multiple taxa by using this bookmarklet again after clicking "Submit"</i></p>
        </form>
    </div>
</div>

This is wonderful! I tried out this new code and it works great. Thank you both for going further on this.