Skip to content

Instantly share code, notes, and snippets.

@xpl
Created February 2, 2025 18:29
Userscript adding a quick Hide button to Zillow thumbnails
// ==UserScript==
// @name Zillow Hide Home Button
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Adds a hide button to each property thumbnail next to the "save" button on Zillow search pages.
// @author Your Name
// @match https://www.zillow.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
/**
* Adds a "Hide" button to the given save area element.
* @param {Element} saveArea - The DOM element containing the save button.
*/
function addHideButton(saveArea) {
// Prevent adding duplicate buttons.
if (saveArea.querySelector('.zillow-hide-button')) return;
// Create the hide button.
const hideBtn = document.createElement('button');
hideBtn.textContent = 'Hide';
hideBtn.className = 'zillow-hide-button';
// Optional inline styling – adjust as needed.
hideBtn.style.marginTop = '8px';
hideBtn.style.marginRight = '20px';
hideBtn.style.padding = '2px 6px';
hideBtn.style.fontSize = '12px';
hideBtn.style.cursor = 'pointer';
hideBtn.style.opacity = 0.33;
hideBtn.addEventListener('click', async function(event) {
event.stopPropagation();
event.preventDefault();
// Find the property card. In Zillow’s markup, the property card is an <article>
// with an id like "zpid_441734523" or a data-test attribute.
const propertyCard = saveArea.closest('article[data-test="property-card"]');
if (!propertyCard) {
console.error('Could not locate the property card.');
return;
}
// Extract the property ID from the card’s id attribute.
let propertyId = propertyCard.id; // expected to be like "zpid_441734523"
if (propertyId && propertyId.indexOf('zpid_') === 0) {
propertyId = propertyId.replace('zpid_', '');
} else {
console.error('Property ID not found or unexpected format:', propertyCard.id);
return;
}
if (!confirm("Sure?")) return;
// Give feedback to the user.
hideBtn.disabled = true;
hideBtn.textContent = 'Hiding...';
try {
// Send the hide request.
const response = await fetch("https://www.zillow.com/zg-graph?operationName=hideHome", {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({
operationName: "hideHome",
variables: { propertyId: propertyId, propertyIdType: "zpid" },
query: "mutation hideHome($propertyId: ID!, $propertyIdType: PropertyIdType!) {\n hideHome(\n hiddenHomeInput: {propertyId: $propertyId, propertyIdType: $propertyIdType}\n )\n}\n"
})
});
const result = await response.json();
console.log('hideHome response:', result);
// Optionally remove the card from view.
propertyCard.style.display = 'none';
} catch (error) {
console.error('Error hiding home:', error);
hideBtn.textContent = 'Error';
}
});
// Append the hide button to the save area.
saveArea.appendChild(hideBtn);
}
/**
* Processes all property cards currently in the DOM.
*/
function processPropertyCards() {
// Zillow uses dynamic class names but the save area always contains "StyledPropertyCardSaveArea".
const saveAreas = document.querySelectorAll('[class*="StyledPropertyCardSaveArea"]');
saveAreas.forEach(saveArea => addHideButton(saveArea));
}
// Run on initial page load.
processPropertyCards();
// Observe DOM changes to add hide buttons to newly loaded cards.
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
// Look for any save areas within newly added nodes.
const newSaveAreas = node.querySelectorAll('[class*="StyledPropertyCardSaveArea"]');
newSaveAreas.forEach(saveArea => addHideButton(saveArea));
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment