Force X/Twitter to xcancel.com

Redirects x.com and twitter.com to xcancel.com (preserves path, query, and hash). Skips OAuth to avoid breaking auth flows.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Force X/Twitter to xcancel.com
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Redirects x.com and twitter.com to xcancel.com (preserves path, query, and hash). Skips OAuth to avoid breaking auth flows.
// @author       you
// @match        https://x.com/*
// @match        https://twitter.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  const host = window.location.host;
  const path = window.location.pathname || '/';
  const search = window.location.search || '';
  const hash = window.location.hash || '';
  const href = window.location.href;

  const isOnXOrTwitter = host === 'x.com' || host === 'twitter.com';
  const isOAuthUrl = () => {
    // Keep this conservative: do NOT redirect OAuth/authorize flows.
    // Common paths: /i/oauth2/authorize, /oauth, /oauth2
    const p = path.toLowerCase();
    return p.includes('/i/oauth2/authorize') || p === '/oauth' || p.startsWith('/oauth2');
  };

  const redirectToXCancel = () => {
    const newUrl = `https://xcancel.com${path}${search}${hash}`;
    if (newUrl !== href) {
      window.location.replace(newUrl);
    }
  };

  if (isOnXOrTwitter) {
    if (isOAuthUrl()) {
      // Do not modify OAuth flows to prevent breaking logins/app authorization.
      return;
    }
    redirectToXCancel();
  }
})();