1<!DOCTYPE html><html lang="en"><head> 2 <!-- Analytics will be loaded after DOM ready for better performance --> 3 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 6
6<script type="text/javascript" async="" src="https://www.clarity.ms/tag/txssedjw3f?ref=gtm"></script>
6<script type="text/javascript" async="" src="https://www.googletagmanager.com/gtag/js?id=G-VXZQGNBXN9&cx=c&gtm=4e69u2"></script>
6<script async="" src="https://www.googletagmanager.com/gtm.js?id=GTM-TZZ5448V"></script>
6<script type="text/javascript" async="" src="//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js"></script>
6<script> 7 (function () { 8 var protocol = window.location && window.location.protocol; 9 var isNativeShell = protocol === "capacitor:" || protocol === "ionic:"; 10 11 if (!isNativeShell) { 12 return; 13 } 14 15 document.documentElement.classList.add("native-capacitor-shell"); 16 17 function clearNativeStartupRoot() { 18 var root = document.getElementById("root"); 19 if (!root) { 20 return false; 21 } 22 23 var hasPrerenderedContent = 24 root.getAttribute("data-prerendered") === "true"; 25 var hasStartupLoader = !!root.querySelector("#loading-indicator"); 26 27 if (!hasPrerenderedContent && !hasStartupLoader) { 28 return false; 29 } 30 31 root.innerHTML = ""; 32 root.removeAttribute("data-prerendered"); 33 root.removeAttribute("style"); 34 root.setAttribute("data-native-startup-cleared", "true"); 35 return true; 36 } 37 38 if (!clearNativeStartupRoot()) { 39 var observer = new MutationObserver(function () { 40 if (clearNativeStartupRoot()) { 41 observer.disconnect(); 42 } 43 }); 44 45 observer.observe(document.documentElement, { 46 childList: true, 47 subtree: true, 48 }); 49 50 document.addEventListener( 51 "DOMContentLoaded", 52 function () { 53 clearNativeStartupRoot(); 54 observer.disconnect(); 55 }, 56 { once: true } 57 ); 58 } 59 })(); 60 </script>
60 61 <style> 62 html.native-capacitor-shell #root[data-prerendered="true"] { 63 visibility: hidden !important; 64 opacity: 0 !important; 65 } 66 </style> 67 68 <!-- Safari Compatibility Meta Tags --> 69 <meta name="format-detection" content="telephone=no"> 70 <meta name="apple-mobile-web-app-capable" content="yes"> 71 <meta name="apple-mobile-web-app-status-bar-style" content="default"> 72 <meta name="apple-touch-fullscreen" content="yes"> 73 74 <!-- Additional Safari iOS Support --> 75 <meta name="mobile-web-app-capable" content="yes"> 76 <meta name="apple-mobile-web-app-title" content="REPSShield"> 77 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 78 <!-- SEO Meta Tags --> 79 <meta name="description" content="Professional IRS REP tracking software to track REP hours and maintain IRS compliance. Comprehensive real estate professional time tracking with audit-ready reports for REP status qualification."> 80 <meta name="keywords" content="IRS REP tracking, track REP hours, IRS compliance tools, real estate professional, REP status, time tracking, material participation, audit compliance"> 81 <meta name="author" content="REPSShield"> 82 <meta name="robots" content="index, follow"> 83 84 <!-- Open Graph Meta Tags --> 85 <meta property="og:title" content="IRS REP Tracking & Compliance Tools | REPSShield"> 86 <meta property="og:description" content="Track REP hours with professional IRS compliance tools. Secure time tracking software for real estate professionals seeking REP status qualification."> 87 <meta property="og:type" content="website"> 88 <meta property="og:image" content="https://repsshield.com/repsshield-logo-main.png"> 89 <meta property="og:url" content=""> 90 <meta property="og:locale" content="en_US"> 91 <meta property="og:site_name" content="REPSShield"> 92 93 <!-- Twitter Card Meta Tags --> 94 <meta name="twitter:card" content="summary_large_image"> 95 <meta name="twitter:title" content="IRS REP Tracking & Compliance Tools | REPSShield"> 96 <meta name="twitter:description" content="Professional software to track REP hours and maintain IRS compliance for real estate professionals."> 97 <meta name="twitter:image" content="https://repsshield.com/repsshield-logo-main.png"> 98 99 <!-- Google Workspace Domain Verification --> 100 <meta name="google-site-verification" content="cqP-09PR0BaU2WIhFBeqgZVvytDSELFNgi81gP7DLYc"> 101 102 <!-- Technical Meta Tags --> 103 <meta name="theme-color" content="#55b021"> 104 <meta name="apple-mobile-web-app-capable" content="yes"> 105 <meta name="apple-mobile-web-app-status-bar-style" content="default"> 106 <meta name="apple-mobile-web-app-title" content="REPSShield"> 107 <meta name="mobile-web-app-capable" content="yes"> 108 109 <!-- SEO Technical Tags --> 110 <link rel="canonical" id="canonical-link" href="https://repsshield.com/login"> 111 <meta name="referrer" content="no-referrer-when-downgrade"> 112 <meta http-equiv="content-language" content="en-US"> 113 <meta name="geo.region" content="US"> 114 <meta name="geo.placename" content="United States"> 115 116 <!-- Resource Links --> 117 <link rel="icon" type="image/x-icon" href="/favicon.ico"> 118 <link rel="shortcut icon" href="/favicon.png"> 119 <link rel="apple-touch-icon" href="/repsshield-logo-main.png"> 120 <link rel="manifest" href="/manifest.json"> 121 <link rel="sitemap" type="application/xml" href="/sitemap.xml"> 122 123 <!-- LunchMoney Style System with performance optimization --> 124 <link rel="stylesheet" href="/style.css" media="all"> 125 126 <!-- Performance: Preload critical CSS --> 127 <link rel="stylesheet" href="/style.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> 128 <noscript><link rel="stylesheet" href="/style.css" /></noscript> 129 130 <title> 131 IRS REP Tracking & Compliance Tools | Track REP Hours | REPSShield 132 </title> 133 134 <!-- Performance Optimization: Resource Hints --> 135 <link rel="preconnect" href="https://www.googletagmanager.com" crossorigin=""> 136 <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin="">
137 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin=""> 138 <link rel="dns-prefetch" href="//www.google-analytics.com"> 139 <link rel="preconnect" href="https://cdn.amplitude.com" crossorigin=""> 140 141 <!-- Deferred Google Tag Manager for better performance --> 142
142<script> 143 // Defer GTM loading until after page load for better performance 144 window.addEventListener("load", function () { 145 (function (w, d, s, l, i) { 146 w[l] = w[l] || []; 147 w[l].push({ 148 "gtm.start": new Date().getTime(), 149 event: "gtm.js", 150 }); 151 var f = d.getElementsByTagName(s)[0], 152 j = d.createElement(s), 153 dl = l != "dataLayer" ? "&l=" + l : ""; 154 j.async = true; 155 j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl; 156 f.parentNode.insertBefore(j, f); 157 })(window, document, "script", "dataLayer", "GTM-TZZ5448V"); 158 }); 159 </script>
159 160 161 <!-- Structured Data for SEO --> 162
162<script type="application/ld+json"> 163 { 164 "@context": "https://schema.org", 165 "@type": "SoftwareApplication", 166 "name": "REPSShield", 167 "applicationCategory": "BusinessApplication", 168 "description": "Professional IRS REP tracking software to track REP hours and maintain IRS compliance for real estate professionals", 169 "url": "https://repsshield.com", 170 "operatingSystem": "Web Browser", 171 "softwareVersion": "1.0", 172 "offers": { 173 "@type": "Offer", 174 "price": "5.00", 175 "priceCurrency": "USD", 176 "priceValidUntil": "2026-12-31" 177 }, 178 "applicationSubCategory": "Time Tracking Software", 179 "featureList": [ 180 "IRS REP tracking", 181 "Track REP hours", 182 "IRS compliance tools", 183 "Material participation tracking", 184 "Audit-ready reports", 185 "Real estate professional time tracking" 186 ], 187 "creator": { 188 "@type": "Organization", 189 "name": "REPSShield", 190 "url": "https://repsshield.com" 191 } 192 } 193 </script>
193 194
vendor: 3,251 bytes, lines 194-270
194<script type="text/javascript"> 195 (function (e, c) { 196 if (!c.__SV) { 197 var l, h; 198 window.mixpanel = c; 199 c._i = []; 200 c.init = function (q, r, f) { 201 function t(d, a) { 202 var g = a.split("."); 203 2 == g.length && ((d = d[g[0]]), (a = g[1])); 204 d[a] = function () { 205 d.push([a].concat(Array.prototype.slice.call(arguments, 0))); 206 }; 207 } 208 var b = c; 209 "undefined" !== typeof f ? (b = c[f] = []) : (f = "mixpanel"); 210 b.people = b.people || []; 211 b.toString = function (d) { 212 var a = "mixpanel"; 213 "mixpanel" !== f && (a += "." + f); 214 d || (a += " (stub)"); 215 return a; 216 }; 217 b.people.toString = function () { 218 return b.toString(1) + ".people (stub)"; 219 }; 220 l = 221 "disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders start_session_recording stop_session_recording people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split( 222 " " 223 ); 224 for (h = 0; h < l.length; h++) t(b, l[h]); 225 var n = "set set_once union unset remove delete".split(" "); 226 b.get_group = function () { 227 function d(p) { 228 a[p] = function () { 229 b.push([ 230 g, 231 [p].concat(Array.prototype.slice.call(arguments, 0)), 232 ]); 233 }; 234 } 235 for ( 236 var a = {}, 237 g = ["get_group"].concat( 238 Array.prototype.slice.call(arguments, 0) 239 ), 240 m = 0; 241 m < n.length; 242 m++ 243 ) 244 d(n[m]); 245 return a; 246 }; 247 c._i.push([q, r, f]); 248 }; 249 c.__SV = 1.2; 250 var k = e.createElement("script"); 251 k.type = "text/javascript"; 252 k.async = !0; 253 k.src = 254 "undefined" !== typeof MIXPANEL_CUSTOM_LIB_URL 255 ? MIXPANEL_CUSTOM_LIB_URL 256 : "file:" === e.location.protocol && 257 "//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//) 258 ? "https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js" 259 : "//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js"; 260 e = e.getElementsByTagName("script")[0]; 261 e.parentNode.insertBefore(k, e); 262 } 263 })(document, window.mixpanel || []); 264 mixpanel.init("edfe0ecd8c675dbbc5d0103ee433f5e5", { 265 autocapture: true, 266 // Session recording consolidated into PostHog â Mixpanel keeps 267 // analytics/autocapture only, it no longer records sessions. 268 record_sessions_percent: 0, 269 }); 270 </script>
270 271 272 <!-- Amplitude Analytics (session replay consolidated into PostHog: 273 the Session Replay plugin is no longer loaded or registered) --> 274
274<script defer="" src="https://cdn.amplitude.com/libs/analytics-browser-2.11.1-min.js.gz"></script>
274 275
275<script> 276 window.addEventListener("load", function () { 277 if (window.amplitude?.init) { 278 window.amplitude.init("c705623f4bce3f86b242ede807f4c23e", { 279 autocapture: { elementInteractions: true }, 280 }); 281 } 282 }); 283 </script>
283 284
284<script type="module" crossorigin="" src="/assets/index-DGo-vssZ.js"></script>
284 285 <link rel="modulepreload" crossorigin="" href="/assets/vendor-Qgthw7N1.js"> 286 <link rel="stylesheet" crossorigin="" href="/assets/index-C2doZrJs.css"> 287 <style id="immediate-overlay-kill"> 288 vite-error-overlay, 289 [data-type="error"], 290 .error-overlay { 291 display: none !important; 292 visibility: hidden !important; 293 opacity: 0 !important; 294 pointer-events: none !important; 295 z-index: -999999 !important; 296 } 297 #root { display: block !important; visibility: visible !important; opacity: 1 !important; } 298 body { pointer-events: auto !important; visibility: visible !important; opacity: 1 !important; } 299 </style>
vendor: 67 bytes, line 299
299<script src="https://www.google.com/recaptcha/enterprise.js?render=
2996LdyvaorAAAAACV4Fsr2EadWDEICggtxuL2gjdI6
vendor: 29 bytes, line 299
299" async="" defer=""></script>
299<script defer="" data-domain="repsshield.com" data-api="https://plausible.io/api/event" src="https://plausible.io/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js"></script>
299</head> 300 <body class="wallpaper-bg"> 301 <!-- Google Tag Manager (noscript) -->
vendor: 80 bytes, lines 301-303
301 302 <noscript><iframe 303 src="https://www.googletagmanager.com/ns.html?id=
303GTM-TZZ5448V
vendor: 126 bytes, lines 303-309
303" 304 height="0" 305 width="0" 306 style="display: none; visibility: hidden" 307 ></iframe 308 ></noscript> 309
309<!-- End Google Tag Manager (noscript) --> 310 311 <!-- Debug: Ensure body and root are visible --> 312 <style> 313 body { 314 visibility: visible !important; 315 opacity: 1 !important; 316 display: block !important; 317 background-color: #f7f7f7; 318 } 319 #root { 320 visibility: visible !important; 321 opacity: 1 !important; 322 display: block !important; 323 min-height: 100vh; 324 } 325 .native-startup-shell { 326 min-height: 100vh; 327 display: flex; 328 align-items: center; 329 justify-content: center; 330 background: #f7f7f7; 331 color: #111827; 332 font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; 333 padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom)); 334 } 335 .native-startup-mascot-wrap { 336 position: relative; 337 display: inline-flex; 338 flex-direction: column; 339 align-items: center; 340 margin: 16px 0 24px; 341 } 342 .native-startup-mascot { 343 width: 96px; 344 height: 96px; 345 -o-object-fit: contain; 346 object-fit: contain; 347 animation: native-startup-bounce 1.4s ease-in-out infinite; 348 } 349 .native-startup-shadow { 350 width: 64px; 351 height: 12px; 352 margin-top: 8px; 353 border-radius: 999px; 354 background: rgba(0, 0, 0, 0.18); 355 filter: blur(2px); 356 animation: native-startup-shadow 1.4s ease-in-out infinite; 357 } 358 @keyframes native-startup-bounce { 359 0%, 100% { transform: translateY(0); } 360 50% { transform: translateY(-14px); } 361 } 362 @keyframes native-startup-shadow { 363 0%, 100% { transform: scale(1); opacity: 0.2; } 364 50% { transform: scale(0.72); opacity: 0.1; } 365 } 366 </style> 367 368 <div id="root" data-prerendered="true"><div class="min-h-screen flex flex-col" data-prerendered="true"><main class="flex-1"><div class="h-[100dvh] min-h-[100dvh] w-full flex items-center justify-center overflow-hidden px-4 py-3 sm:p-4" style="background: transparent; padding-top: max(0.75rem, env(safe-area-inset-top)); padding-bottom: max(0.75rem, env(safe-area-inset-bottom));"><div class="w-full max-w-md"><div class="rounded-xl bg-card text-card-foreground transition-all duration-200 w-full shadow-lg border border-gray-200" style="transform: scale(1); transform-origin: center top;"><div class="flex flex-col space-y-1.5 p-6 text-center pb-3 sm:pb-6"><div class="mascot-container login-mascot-container"><img src="/repsshield-logo-main.png" alt="REPSShield" class="bouncing-mascot login-mascot"><div class="mascot-shadow"></div></div><div class="tracking-tight text-2xl sm:text-3xl font-bold">Welcome Back!</div></div><div class="p-6 pt-0 space-y-3 sm:space-y-6"><div class="space-y-2 sm:space-y-3"><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 touch-manipulation active:scale-[0.97] active:opacity-90 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-12 px-4 py-2 sm:h-10 w-full"><svg class="w-4 h-4 mr-2" viewBox="0 0 24 24"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"></path><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"></path><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"></path><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"></path></svg>Continue with Google</button><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 touch-manipulation active:scale-[0.97] active:opacity-90 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-12 px-4 py-2 sm:h-10 w-full"><svg class="w-4 h-4 mr-2" viewBox="0 0 24 24">
368<path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" fill="currentColor"></path></svg>Continue with Apple</button></div><div class="relative"><div class="absolute inset-0 flex items-center"><div data-orientation="horizontal" role="none" class="shrink-0 bg-border h-[1px] w-full"></div></div><div class="relative flex justify-center text-xs uppercase"><span class="bg-white px-2 text-gray-500">Or continue with email</span></div></div><form class="space-y-3 sm:space-y-4"><div class="space-y-2"><label class="text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for=":r3:-form-item">Email</label><input type="email" class="flex w-full border border-input bg-background px-3 py-2 ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 h-12 sm:h-10 text-base sm:text-sm rounded-xl sm:rounded-md touch-manipulation" placeholder="[email protected]" autocomplete="email" name="email" id=":r3:-form-item" aria-describedby=":r3:-form-item-description" aria-invalid="false" value=""></div><div class="space-y-2"><label class="text-base font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for=":r4:-form-item">Password</label><div class="relative" id=":r4:-form-item" aria-describedby=":r4:-form-item-description" aria-invalid="false"><input type="password" class="flex w-full border border-input bg-background px-3 py-2 ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 h-12 sm:h-10 text-base sm:text-sm rounded-xl sm:rounded-md touch-manipulation" placeholder="Enter your password" name="password" value=""><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 touch-manipulation active:scale-[0.97] active:opacity-90 hover:text-accent-foreground rounded-md sm:h-9 absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-eye h-4 w-4"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"></path><circle cx="12" cy="12" r="3"></circle></svg></button></div></div><div class="text-right"><button type="button" class="text-sm text-[#44958c] hover:text-[#367068] underline">Forgot password?</button></div><div class="flex items-center justify-center space-x-2 py-1 sm:py-2"><div class="flex items-center space-x-2 text-gray-400"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-loader-circle w-4 h-4 animate-spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg><span class="text-sm">Loading security verification...</span></div></div><button class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 touch-manipulation active:scale-[0.97] active:opacity-90 bg-primary text-primary-foreground hover:bg-primary/90 h-12 px-4 py-2 sm:h-10 w-full" t
368ype="submit">Sign In</button></form><div class="text-center"><button type="button" class="text-sm text-[#44958c] hover:text-[#367068] underline">Don't have an account? Sign up</button></div></div></div></div></div></main></div><div role="region" aria-label="Notifications (F8)" tabindex="-1" style="pointer-events: none;"><ol tabindex="-1" class="fixed top-0 z-[11000] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]"></ol></div></div> 369 370 371 372 <!-- Performance Optimized React Pre-Initialization --> 373
373<script type="text/javascript" crossorigin="anonymous" src="https://us-assets.i.posthog.com/static/1.435.3/surveys.js"></script>
373<script type="text/javascript" crossorigin="anonymous" src="https://us-assets.i.posthog.com/array/phc_x5APwUeWZHhqtjerPtcWNqvv2PQN5EsWdYHsqXj9tgwx/config.js"></script>
373<script type="text/javascript" crossorigin="anonymous" src="https://us-assets.i.posthog.com/static/1.435.3/dead-clicks-autocapture.js"></script>
373<script type="text/javascript" crossorigin="anonymous" src="https://us-assets.i.posthog.com/static/1.435.3/posthog-recorder.js"></script>
373<script type="text/javascript" crossorigin="anonymous" src="https://us-assets.i.posthog.com/static/1.435.3/web-vitals-with-attribution.js"></script>
373<script defer=""> 374 // Optimize: Defer execution until DOM is parsed 375 document.addEventListener("DOMContentLoaded", function () { 376 // Environment detection 377 const isDevUrl = !window.parent || window.parent === window; 378 const isPreview = window.parent && window.parent !== window; 379 380 381 382 // Create React namespace with complete hooks implementation IMMEDIATELY 383 window.React = { 384 // Core hooks that the plugin tries to access 385 useState: function (initialState) { 386 387 let state = initialState; 388 const setState = (newState) => { 389 state = 390 typeof newState === "function" ? newState(state) : newState; 391 }; 392 return [state, setState]; 393 }, 394 395 useEffect: function (effect, deps) { 396 397 try { 398 if (typeof effect === "function") { 399 const cleanup = effect(); 400 if (typeof cleanup === "function") { 401 setTimeout(cleanup, 0); 402 } 403 } 404 } catch (e) { 405 console.warn("IMMEDIATE: useEffect error handled safely:", e); 406 } 407 }, 408 409 useRef: function (initialValue) { 410 411 return { current: initialValue }; 412 }, 413 414 useContext: function (context) { 415 416 return context?._currentValue || null; 417 }, 418 419 useReducer: function (reducer, initialState) { 420 421 let state = initialState; 422 const dispatch = (action) => { 423 try { 424 state = reducer(state, action); 425 } catch (e) { 426 console.warn("IMMEDIATE: useReducer error handled:", e); 427 } 428 }; 429 return [state, dispatch]; 430 }, 431 432 useCallback: function (callback, deps) { 433 434 return callback; 435 }, 436 437 useMemo: function (factory, deps) { 438 439 try { 440 return factory(); 441 } catch (e) { 442 console.warn("IMMEDIATE: useMemo error handled:", e); 443 return null; 444 } 445 }, 446 447 // Additional React properties that might be accessed 448 createElement: function (type, props, ...children) { 449 return { 450 type, 451 props: { 452 ...props, 453 children: children.length === 1 ? children[0] : children, 454 }, 455 key: props?.key || null, 456 ref: props?.ref || null, 457 }; 458 }, 459 460 Component: class Component { 461 constructor(props) { 462 this.props = props; 463 this.state = {}; 464 } 465 setState(partialState) { 466 this.state = { ...this.state, ...partialState }; 467 } 468 render() { 469 return null; 470 } 471 }, 472 473 Fragment: "React.Fragment", 474 version: "18.0.0", 475 }; 476 477 // Ensure React hooks are NEVER null by overriding property access 478 const reactProxy = new Proxy(window.React, { 479 get(target, prop) { 480 if (target[prop]) { 481 return target[prop]; 482 } 483 484 // If a hook is accessed that we haven't defined, provide a safe fallback 485 if (prop.startsWith("use")) { 486 487 return function (...args) { 488 console.warn( 489 `IMMEDIATE: Safe fallback ${prop} called with:`, 490 args 491 ); 492 return prop === "useState" 493 ? [null, () => {}] 494 : prop === "useRef" 495 ? { current: null } 496 : null; 497 }; 498 } 499 500 return target[prop]; 501 }, 502 }); 503 504 window.React = reactProxy; 505 506 // Enhanced global error suppression for plugin errors including wallet extensions 507 window.addEventListener( 508 "error", 509 function (event) { 510 const message = event.message || ""; 511 const filename = event.filename || ""; 512 513 // Suppress React hook null access errors 514 if ( 515 message.includes("Cannot read properties of null") && 516 (message.includes("useEffect") || message.includes("useState")) 517 ) { 518 console.log( 519 "IMMEDIATE: Prevented plugin null access error from displaying" 520 ); 521 event.preventDefault(); 522 event.stopPropagation(); 523 return false;
524 } 525 526 // Suppress browser extension property redefinition errors 527 if ( 528 message.includes("Cannot redefine property") && 529 filename.includes("extension") 530 ) { 531 console.log( 532 "IMMEDIATE: Prevented browser extension error from displaying" 533 ); 534 event.preventDefault(); 535 event.stopPropagation(); 536 return false; 537 } 538 539 // Suppress browser extension injection errors 540 if ( 541 message.includes("TypeError") && 542 filename.includes("extension") 543 ) { 544 console.log( 545 "IMMEDIATE: Prevented browser extension error from displaying" 546 ); 547 event.preventDefault(); 548 event.stopPropagation(); 549 return false; 550 } 551 }, 552 true 553 ); // Use capture phase to catch early 554 555 // Enhanced console.error suppression for plugin and wallet extension errors 556 const originalConsoleError = console.error; 557 console.error = function (...args) { 558 const message = args.join(" "); 559 560 // Suppress plugin runtime errors 561 if ( 562 message.includes("[plugin:runtime-error-plugin]") && 563 message.includes("Cannot read properties of null") 564 ) { 565 console.warn("IMMEDIATE: Suppressed plugin error message"); 566 return; 567 } 568 569 // Suppress browser extension property errors 570 if ( 571 message.includes("Cannot redefine property") && 572 filename.includes("extension") 573 ) { 574 console.warn( 575 "IMMEDIATE: Suppressed browser extension error message" 576 ); 577 return; 578 } 579 580 originalConsoleError.apply(console, args); 581 }; 582 583 // Immediate overlay suppression 584 const suppressOverlaysImmediately = () => { 585 const overlays = document.querySelectorAll( 586 'vite-error-overlay, [data-type="error"], .error-overlay' 587 ); 588 overlays.forEach((overlay) => { 589 if ( 590 overlay.textContent && 591 overlay.textContent.includes("runtime-error-plugin") 592 ) { 593 overlay.style.display = "none !important"; 594 overlay.remove(); 595 } 596 }); 597 598 // Add permanent CSS suppression 599 if (!document.getElementById("immediate-overlay-kill")) { 600 const style = document.createElement("style"); 601 style.id = "immediate-overlay-kill"; 602 style.textContent = ` 603 vite-error-overlay, 604 [data-type="error"], 605 .error-overlay { 606 display: none !important; 607 visibility: hidden !important; 608 opacity: 0 !important; 609 pointer-events: none !important; 610 z-index: -999999 !important; 611 } 612 #root { display: block !important; visibility: visible !important; opacity: 1 !important; } 613 body { pointer-events: auto !important; visibility: visible !important; opacity: 1 !important; } 614 `; 615 document.head.appendChild(style); 616 } 617 }; 618 619 // Run immediately and continuously for first few seconds 620 suppressOverlaysImmediately(); 621 const immediateInterval = setInterval(suppressOverlaysImmediately, 25); 622 623 // Early detection: Stop suppression as soon as React content appears 624 const earlyDetection = setInterval(() => { 625 const hasAppElements = 626 window.__APP_INITIALIZED__ || 627 document.querySelector( 628 '.bg-background, .min-h-screen, #root > div, .text-center, .dashboard-container, [class*="card"], [class*="container"]' 629 ) || 630 (document.querySelector("#root") && 631 document.querySelector("#root").innerHTML.length > 100); 632 if (hasAppElements) { 633 console.log( 634 "IMMEDIATE: Early React app detection - stopping overlay suppression" 635 ); 636 clearInterval(immediateInterval);
637 clearInterval(earlyDetection); 638 } 639 }, 200); // Check every 200ms for early detection 640 641 // Stop after React app loads or timeout (Safari gets special treatment) 642 const isSafari = 643 /Safari/.test(navigator.userAgent) && 644 !/Chrome/.test(navigator.userAgent); 645 const timeoutDuration = isSafari ? 60000 : 45000; // Safari gets 60s, others get 45s 646 647 setTimeout(() => { 648 const hasAppElements = 649 window.__APP_INITIALIZED__ || 650 document.querySelector( 651 '.bg-background, .min-h-screen, #root > div, .text-center, .dashboard-container, [class*="card"], [class*="container"]' 652 ) || 653 (document.querySelector("#root") && 654 document.querySelector("#root").innerHTML.length > 100); 655 656 console.log( 657 "IMMEDIATE: Timeout check - App elements found:", 658 hasAppElements 659 ); 660 console.log( 661 "IMMEDIATE: Available elements:", 662 document.querySelector("#root") 663 ? document.querySelector("#root").innerHTML.length + 664 " chars in root" 665 : "No root element" 666 ); 667 668 if (hasAppElements) { 669 console.log( 670 "IMMEDIATE: React app loaded successfully, stopping overlay suppression" 671 ); 672 clearInterval(immediateInterval); 673 clearInterval(earlyDetection); 674 } else { 675 console.log( 676 "IMMEDIATE: React app failed to load after " + 677 timeoutDuration / 1000 + 678 "s - applying fallback strategy" 679 ); 680 clearInterval(immediateInterval); 681 clearInterval(earlyDetection); 682 683 // For mobile devices, especially Safari and post-OAuth, handle specially 684 const isMobile = /Mobi|Android|iPhone|iPad/i.test( 685 navigator.userAgent 686 ); 687 const isAfterOAuth = 688 document.referrer.includes("/api/auth/") || 689 window.location.search.includes("code=") || 690 sessionStorage.getItem("oauth-in-progress") === "true" || 691 sessionStorage.getItem("oauthFlowInitiated") === "true"; 692 693 // Clear OAuth flags 694 sessionStorage.removeItem("oauth-in-progress"); 695 sessionStorage.removeItem("oauthFlowInitiated"); 696 697 // Safari NEVER goes to static page - always reloads or redirects to login 698 if (isSafari) { 699 console.log( 700 "IMMEDIATE: Safari detected - NEVER redirecting to static page" 701 ); 702 console.log( 703 "IMMEDIATE: Safari fallback - redirecting to login page for fresh auth check" 704 ); 705 window.location.href = "/login"; 706 } else if (isMobile || isAfterOAuth) { 707 console.log( 708 "IMMEDIATE: Mobile/post-OAuth detected - reloading page instead of static redirect" 709 ); 710 console.log( 711 "IMMEDIATE: isMobile:", 712 isMobile, 713 "isAfterOAuth:", 714 isAfterOAuth 715 ); 716 window.location.reload(); 717 } else { 718 console.log( 719 "IMMEDIATE: Desktop device - redirecting to login for auth check" 720 ); 721 window.location.href = "/login"; 722 } 723 } 724 }, timeoutDuration); 725 726 727 728 // Fix canonical URL to reflect current page URL 729 // Always uses the production base and strips trailing slashes so 730 // /blog/slug and /blog/slug/ resolve to the same canonical URL. 731 const canonicalLink = document.getElementById("canonical-link"); 732 if (canonicalLink) { 733 let currentPath = location.pathname; 734 if (currentPath.length > 1 && currentPath.endsWith("/")) { 735 currentPath = currentPath.slice(0, -1); 736 } 737 const correctUrl = `https://repsshield.com${currentPath}`; 738 canonicalLink.setAttribute("href", correctUrl); 739 } 740 }); // End DOMContentLoaded 741 </script>
741 742 743 <!-- Performance Monitoring and Optimization --> 744
744<script> 745 // Critical Web Vitals monitoring 746 const observer = new PerformanceObserver((list) => { 747 for (const entry of list.getEntries()) { 748 if (entry.entryType === "measure") { 749 750 } 751 } 752 }); 753 observer.observe({ entryTypes: ["measure"] }); 754 755 // Lazy load non-critical images 756 if ("IntersectionObserver" in window) { 757 const imageObserver = new IntersectionObserver((entries, observer) => { 758 entries.forEach((entry) => { 759 if (entry.isIntersecting) { 760 const img = entry.target; 761 img.src = img.dataset.src; 762 img.classList.remove("lazy"); 763 imageObserver.unobserve(img); 764 } 765 }); 766 }); 767 768 document.addEventListener("DOMContentLoaded", () => { 769 document.querySelectorAll("img[data-src]").forEach((img) => { 770 imageObserver.observe(img); 771 }); 772 }); 773 } 774 </script>
774 775 776 <!-- Optimized Post-OAuth Analytics Loading --> 777
777<script defer=""> 778 // Performance-optimized analytics loading for post-OAuth scenarios 779 window.deferredAnalyticsLoad = function () { 780 781 782 // Google Tag Manager - Load after dashboard render 783 (function (w, d, s, l, i) { 784 w[l] = w[l] || []; 785 w[l].push({ 786 "gtm.start": new Date().getTime(), 787 event: "gtm.js", 788 }); 789 var f = d.getElementsByTagName(s)[0], 790 j = d.createElement(s), 791 dl = l != "dataLayer" ? "&l=" + l : ""; 792 j.async = true; 793 j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl; 794 f.parentNode.insertBefore(j, f); 795 })(window, document, "script", "dataLayer", "GTM-TZZ5448V"); 796 797 // Umami Analytics - Deferred to post-dashboard render using requestIdleCallback 798 function loadUmami() { 799 800 var umamiScript = document.createElement("script"); 801 umamiScript.defer = true; 802 umamiScript.src = "https://cloud.umami.is/script.js"; 803 umamiScript.setAttribute( 804 "data-website-id", 805 "0473b837-662f-4cd9-ada3-b65b89dc1e73" 806 ); 807 umamiScript.onload = function () { 808 809 }; 810 umamiScript.onerror = function () { 811 console.warn("[Analytics] Umami analytics failed to load"); 812 }; 813 document.head.appendChild(umamiScript); 814 } 815 816 // Use requestIdleCallback to load Umami when browser is idle (after dashboard render) 817 if (window.requestIdleCallback) {
818 window.requestIdleCallback(loadUmami, { timeout: 3000 }); 819 } else { 820 setTimeout(loadUmami, 1500); // Fallback with 1.5s delay 821 } 822 }; 823 824 // Global performance optimization for ALL pages 825 window.addEventListener("DOMContentLoaded", function () { 826 // For ALL pages (public and authenticated), defer analytics to improve performance 827 console.log( 828 "[Analytics] Page loaded - deferring analytics for optimal performance" 829 ); 830 831 // Always use maximum delay for public pages performance 832 const isPublicPage = 833 ["/features", "/pricing", "/why-reps-shield", "/about"].includes( 834 window.location.pathname 835 ) || window.location.pathname.startsWith("/features/"); 836 837 if (isPublicPage) { 838 console.log( 839 "[Analytics] Public page detected - maximum deferral for speed" 840 ); 841 // For public marketing pages, defer analytics heavily to maximize page speed 842 if (window.requestIdleCallback) { 843 window.requestIdleCallback(window.deferredAnalyticsLoad, { 844 timeout: 5000, 845 }); 846 } else { 847 setTimeout(window.deferredAnalyticsLoad, 2000); // 2s delay for public pages 848 } 849 } else if ( 850 window.location.pathname === "/" || 851 window.location.hash === "#/" 852 ) { 853 console.log( 854 "[Analytics] Dashboard detected - deferring analytics until after render" 855 ); 856 // Wait for dashboard to be fully rendered before loading analytics 857 function waitForDashboard() { 858 if ( 859 document.querySelector( 860 '[data-testid="dashboard-content"], .dashboard-container, .min-h-screen' 861 ) 862 ) { 863 864 window.deferredAnalyticsLoad(); 865 } else { 866 setTimeout(waitForDashboard, 100); 867 } 868 } 869 setTimeout(waitForDashboard, 500); // Give dashboard time to start rendering 870 } else { 871 // For other pages, load analytics with moderate delay 872 if (window.requestIdleCallback) { 873 window.requestIdleCallback(window.deferredAnalyticsLoad, { 874 timeout: 3000, 875 }); 876 } else { 877 setTimeout(window.deferredAnalyticsLoad, 1000); 878 } 879 } 880 }); 881 </script>
881 882 <!-- This is a replit script which adds a banner on the top of the page when opened in development mode outside the replit environment --> 883 <!-- Commented out to prevent blue debug banner showing in production 884
884<script type="text/javascript" src="https://replit.com/public/js/replit-dev-banner.js"></script>
884 885 --> 886 887 <!-- React App Entry Point - MUST be last to ensure all scripts are loaded first --> 888 889 890
891<script type="text/javascript" id="" charset="">var script=document.createElement("script");script.defer=!0;script.dataset.domain="repsshield.com";script.dataset.api="https://plausible.io/api/event";script.src="https://plausible.io/js/script.file-downloads.hash.outbound-links.pageview-props.revenue.tagged-events.js";document.getElementsByTagName("head")[0].appendChild(script);</script>
891 892
893<script type="text/javascript" id="" charset="">window.plausible=window.plausible||function(){(window.plausible.q=window.plausible.q||[]).push(arguments)};</script>
893 894</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.