1 2<!DOCTYPE html> 3<html lang="en"> 4<head> 5 <meta charset="UTF-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 <title>Sign In to Offa | Access Off-Market Real Estate Deals</title> 8 9<meta name="description" content="Log in to your Offa account to buy and sell off-market properties. Access exclusive wholesale deals, manage listings, and connect with investors." /> 10<meta property="og:title" content="Sign In to Offa | Access Off-Market Real Estate Deals" /> 11<meta property="og:description" content="Log in to your Offa account to buy and sell off-market properties. Access exclusive wholesale deals, manage listings, and connect with investors." /> 12<meta property="og:image" content="https://buybox-prod.s3.amazonaws.com/static/images/Shortcolor.png" /> 13<meta property="og:image:width" content="1200" /> 14<meta property="og:image:height" content="630" /> 15<meta property="og:type" content="website" /> 16<meta property="og:url" content="https://offa.com/login/" /> 17<meta name="twitter:card" content="summary_large_image" /> 18<meta name="twitter:title" content="Sign In to Offa | Access Off-Market Real Estate Deals" /> 19<meta name="twitter:description" content="Log in to your Offa account to buy and sell off-market properties. Access exclusive wholesale deals, manage listings, and connect with investors." /> 20<meta name="twitter:image" content="https://buybox-prod.s3.amazonaws.com/static/images/Shortcolor.png" /> 21 22 <link rel="stylesheet" href="https://buybox-prod.s3.amazonaws.com/static/css/tailwind.css"> 23 <link rel="icon" href="https://buybox-prod.s3.amazonaws.com/static/images/Shortcolor.svg" /> 24 <link rel="preconnect" href="https://fonts.googleapis.com"> 25 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 26 <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet"> 27 28<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/lipis/[email protected]/css/flag-icons.min.css"> 29 30 31 <!-- Sentry Error Tracking --> 32 33
33<script src="https://browser.sentry-cdn.com/8.52.0/bundle.tracing.replay.min.js" crossorigin="anonymous"></script>
33 34
34<script> 35 Sentry.init({ 36 dsn: "https://301403d83a89caff60d814fdfc551b29@o4509202304204800.ingest.us.sentry.io/4509220624007168", 37 environment: "production", 38 integrations: [ 39 Sentry.browserTracingIntegration(), 40 Sentry.replayIntegration({ 41 maskAllText: false, 42 blockAllMedia: false, 43 }), 44 ], 45 tracesSampleRate: 0.1, 46 replaysSessionSampleRate: 0.1, 47 replaysOnErrorSampleRate: 1.0, 48 }); 49 Sentry.setUser({ anonymous: true }); 50 </script>
50 51 52 53 <!-- Capture screen_name block once for reuse --> 54
54<script>window._screenName = 'unified_auth';</script>
54 55 56 <!-- Environment Detection Utility --> 57
57<script> 58 /** 59 * Global utility to detect local/development environment 60 * Used to disable third-party analytics and tracking tools during local development 61 * 62 * Tools controlled by this utility: 63 * - Amplitude Analytics (event tracking) 64 * - Meta Pixel (already controlled by Django settings.ENVIRONMENT check) 65 * 66 * Detects local environments by checking for: 67 * - localhost, 127.0.0.1, 0.0.0.0 68 * - Local network IPs (192.168.x.x, 10.x.x.x) 69 * - .local domains 70 */ 71 window.isLocalEnvironment = function() { 72 // Allow forcing analytics on locally with ?debug_amplitude=true 73 if (new URLSearchParams(window.location.search).has('debug_amplitude')) return false; 74 const hostname = window.location.hostname; 75 return hostname === 'localhost' || 76 hostname === '127.0.0.1' || 77 hostname === '0.0.0.0' || 78 hostname.startsWith('192.168.') || 79 hostname.startsWith('10.') || 80 hostname.endsWith('.local'); 81 }; 82 </script>
82 83 84 <!-- Meta Pixel Code - Production Only --> 85 86
86<script>
vendor: 435 bytes, lines 86-95
86 87 !function(f,b,e,v,n,t,s) 88 {if(f.fbq)return;n=f.fbq=function(){n.callMethod? 89 n.callMethod.apply(n,arguments):n.queue.push(arguments)}; 90 if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0'; 91 n.queue=[];t=b.createElement(e);t.async=!0; 92 t.src=v;s=b.getElementsByTagName(e)[0]; 93 s.parentNode.insertBefore(t,s)}(window, document,'script', 94 'https://connect.facebook.net/en_US/fbevents.js'); 95 fbq('init', '
951152516083506846
vendor: 8 bytes, lines 95-96
95'); 96
96fbq('init', '1521507252682825'); 97 fbq('track', 'PageView', { 98 content_name: window._screenName, 99 content_category: window.location.pathname 100 }); 101 </script>
101 102 <noscript><img height="1" width="1" style="display:none" 103 src="https://www.facebook.com/tr?id=1152516083506846&ev=PageView&noscript=1"/></noscript> 104 <noscript><img height="1" width="1" style="display:none" 105 src="https://www.facebook.com/tr?id=1521507252682825&ev=PageView&noscript=1"/></noscript> 106 107 <!-- End Meta Pixel Code --> 108 109 <!-- TikTok Pixel Code Start --> 110 111
111<script> 112 !function (w, d, t) { 113 w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];ttq.methods=["page","track","identify","instances","debug","on","off","once","ready","alias","group","enableCookie","disableCookie","holdConsent","revokeConsent","grantConsent"],ttq.setAndDefer=function(t,e){t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}};for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);ttq.instance=function(t){for(var e=ttq._i[t]||[],n=0;n<ttq.methods.length;n++)ttq.setAndDefer(e,ttq.methods[n]);return e},ttq.load=function(e,n){var r="https://analytics.tiktok.com/i18n/pixel/events.js",o=n&&n.partner;ttq._i=ttq._i||{},ttq._i[e]=[],ttq._i[e]._u=r,ttq._t=ttq._t||{},ttq._t[e]=+new Date,ttq._o=ttq._o||{},ttq._o[e]=n||{};n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=r+"?sdkid="+e+"&lib="+t;e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(n,e)}; 114 ttq.load('D6NI1B3C77UET383QM9G'); 115 ttq.page(); 116 }(window, document, 'ttq'); 117 </script>
117 118 119 <!-- TikTok Pixel Code End --> 120 121 122 <!-- Google tag (gtag.js) -->
vendor: 73 bytes, lines 122-124
122 123 124 <script async src="https://www.googletagmanager.com/gtag/js?id=
124AW-17974451566
vendor: 18 bytes, lines 124-125
124"></script> 125
125<script> 126
vendor: 152 bytes, lines 126-130
126window.dataLayer = window.dataLayer || []; 127 function gtag(){dataLayer.push(arguments);} 128 gtag('js', new Date()); 129 130 gtag('config', '
130AW-17974451566
vendor: 8 bytes, lines 130-131
130'); 131
131</script>
131 132 133 134 <style> 135 body { font-family: 'Poppins', sans-serif; } 136 137 </style> 138</head> 139<body class="bg-white min-h-screen flex flex-col"> 140 141<div class="flex flex-1 flex-col justify-center items-center px-6 py-8"> 142 <!-- Logo --> 143 <div class="w-full flex justify-center mb-6"> 144 <svg width="246" height="150" viewBox="0 0 346 191" fill="none" xmlns="http://www.w3.org/2000/svg"> 145 <defs> 146 <linearGradient id="paint0_linear_desktop" x1="57.5898" y1="100.709" x2="142.869" y2="100.709" gradientUnits="userSpaceOnUse"> 147 <stop stop-color="#40C057" /> 148 <stop offset="1" stop-color="#175222" /> 149 </linearGradient> 150 </defs> 151 <path d="M206.896 104.786C206.896 97.6416 208.342 91.3899 211.234 86.0313C214.126 80.5876 218.081 76.3773 223.1 73.4003C228.203 70.4233 233.859 68.9348 240.069 68.9348C246.193 68.9348 251.509 70.2532 256.017 72.8899C260.525 75.5267 263.885 78.8439 266.096 82.8416V70.0831L277.834 70.0831V140H266.096V126.986C263.8 131.069 260.355 134.471 255.762 137.193C251.254 139.83 245.98 141.148 239.941 141.148C233.732 141.148 228.118 139.617 223.1 136.555C218.081 133.493 214.126 129.198 211.234 123.669C208.342 118.14 206.896 111.846 206.896 104.786ZM266.096 104.914C266.096 99.6404 265.033 95.0473 262.906 91.1347C260.78 87.2221 257.888 84.2451 254.231 82.2037C250.658 80.0773 246.703 79.0141 242.365 79.0141C238.027 79.0141 234.072 80.0347 230.5 82.0761C226.927 84.1175 224.078 87.0945 221.951 91.0071C219.825 94.9197 218.762 99.5128 218.762 104.786C218.762 110.145 219.825 114.823 221.951 118.821C224.078 122.733 226.927 125.753 230.5 127.879C234.072 129.921 238.027 130.941 242.365 130.941C246.703 130.941 250.658 129.921 254.231 127.879C257.888 125.753 260.78 122.733 262.906 118.821C265.033 114.823 266.096 110.187 266.096 104.914Z" fill="#175222" /> 152 <path d="M174.502 86.7233H161.697V139.391H151.564V86.7233H143.659V78.3722H151.564V74.0297C151.564 67.2003 153.309 62.2268 156.798 59.1091C160.361 55.9171 166.039 54.3211 173.834 54.3211V62.7836C169.38 62.7836 166.225 63.6743 164.369 65.4559C162.588 67.1632 161.697 70.0211 161.697 74.0297V78.3722H174.502V86.7233ZM208.92 86.7233H196.115V139.391H185.982V86.7233L178.076 86.7233V78.3722H185.982V74.0297C185.982 67.2003 187.726 62.2268 191.215 59.1091C194.778 55.9171 200.457 54.3211 208.251 54.3211V62.7836C203.798 62.7836 200.643 63.6743 198.787 65.4559C197.005 67.1632 196.115 70.0211 196.115 74.0297V78.3722H208.92V86.7233Z" fill="#175222" /> 153 <path d="M100.229 61.4609C123.779 61.461 142.869 80.0055 142.869 102.882C142.869 119.115 133.256 133.164 119.259 139.957H81.2002C67.2031 133.164 57.5898 119.115 57.5898 102.882C57.59 80.0054 76.6802 61.4609 100.229 61.4609Z" fill="url(#paint0_linear_desktop)" /> 154 <path d="M99.9277 86.9844C110.497 86.9846 119.065 95.2151 119.065 105.367C119.065 105.622 119.058 105.875 119.047 106.127H119.065V140.333H80.7891V106.127H80.8076C80.7969 105.875 80.7891 105.622 80.7891 105.367C80.7891 95.2149 89.3582 86.9844 99.9277 86.9844Z" fill="#C1FF72" /> 155 <ellipse cx="113.841" cy="120.04" rx="1.7398" ry="2.89967" fill="#1F8D49" /> 156 </svg> 157 </div> 158 159 <!-- Content --> 160 <div class="w-full max-w-md mx-auto"> 161 <div class="text-center mb-6"> 162 <h2 class="text-3xl font-bold text-gray-900">Welcome</h2> 163 <p class="text-gray-500 mt-2">#1 Off-Market Real Estate Marketplace</p> 164 </div> 165 166 <div class="w-full"> 167 <form action="/auth/" method="POST" class="space-y-4" id="authForm"> 168 <input type="hidden" name="csrfmiddlewaretoken" value="L2rYTVqW15dIivQwrVbiMVqxrjpvtaldEbQxGBouyic4jUzSOYOopK87yDD7mWui"> 169 170 171 172 <!-- Phone Input --> 173 <div id="phone-input-group" class="relative "> 174 <div class="flex border border-gray-300 rounded-lg bg-white"> 175 <div class="flex-shrink-0 flex items-center px-3 py-3 border-r border-gray-200 relative"> 176 <span id="flag-display" class="fi fi-us" style="font-size: 20px; margin-right: 8px"></span> 177 <span id="code-display" class="text-gray-700 font-medium">+1</span> 178 <svg class="w-4 h-4 ml-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 179 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> 180 </svg> 181 <select id="country-code" name="country-code" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"> 182 <option value="+1" data-flag="us" selected>+1 (US)</option> 183 </select> 184 </div> 185 <input type="tel" id="phone" name="phone" placeholder="407-987-6784" 186 class="flex-grow px-4 py-3 border-0 focus:outline-none focus:ring-0 bg-transparent text-base" 187 value="" 188 maxlength="12"
189 oninput="formatPhoneNumber(this)" 190 pattern="\d{3}-\d{3}-\d{4}" /> 191 </div> 192 </div> 193 194 <!-- Email Input --> 195 <div id="email-input-group" class="relative hidden"> 196 <input type="email" id="email" name="email" placeholder="Email Address" 197 class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#40C057] text-base" 198 value="" /> 199 </div> 200 201 <button type="submit" 202 class="w-full py-3 bg-gradient-to-r from-[#40C057] to-[#175222] text-white rounded-full hover:from-[#3BB04F] hover:to-[#14601E] transition-all font-medium text-lg"> 203 Continue 204 </button> 205 206 <div class="text-center text-sm text-gray-500"> 207 <a href="#" id="toggle-method" class="text-blue-500 hover:underline"> 208 Use Email instead 209 </a> 210 </div> 211 212 <div class="text-center text-sm text-gray-600 mt-4"> 213 By continuing, you agree to the Offa 214 <a href="/terms-of-service/" target="_blank" class="text-blue-500 hover:underline">Terms of Service</a> 215 and acknowledge you have read the Offa 216 <a href="/privacy-policy/" target="_blank" class="text-blue-500 hover:underline">Privacy Policy</a>. 217 </div> 218 </form> 219 </div> 220 221 </div> 222</div> 223 224 225 <!-- Amplitude Analytics for Auth Pages --> 226
226<script> 227 (function() { 228 if (window.isLocalEnvironment()) { 229 console.log('Amplitude disabled in local environment'); 230 return; 231 } 232 233 // Parse UTM parameters early (no dependency on Amplitude) 234 var urlParams = new URLSearchParams(window.location.search); 235 window.utmParams = { 236 utm_source: urlParams.get('utm_source') || null, 237 utm_medium: urlParams.get('utm_medium') || null, 238 utm_campaign: urlParams.get('utm_campaign') || null, 239 utm_content: urlParams.get('utm_content') || null, 240 utm_term: urlParams.get('utm_term') || null 241 }; 242 243 // Detect ad click IDs (fbclid, gclid, etc.) when no UTMs are present 244 if (!window.utmParams.utm_source) { 245 if (urlParams.get('fbclid')) { 246 window.utmParams.utm_source = 'facebook'; 247 window.utmParams.utm_medium = 'paid_social'; 248 window.utmParams.utm_campaign = 'facebook_ads'; 249 } else if (urlParams.get('gclid') || urlParams.get('gad_source')) { 250 window.utmParams.utm_source = 'google'; 251 window.utmParams.utm_medium = 'cpc'; 252 window.utmParams.utm_campaign = 'google_ads'; 253 } else if (urlParams.get('ttclid')) { 254 window.utmParams.utm_source = 'tiktok'; 255 window.utmParams.utm_medium = 'paid_social'; 256 window.utmParams.utm_campaign = 'tiktok_ads'; 257 } else if (urlParams.get('li_fat_id')) { 258 window.utmParams.utm_source = 'linkedin'; 259 window.utmParams.utm_medium = 'paid_social'; 260 window.utmParams.utm_campaign = 'linkedin_ads'; 261 } else if (urlParams.get('msclkid')) { 262 window.utmParams.utm_source = 'bing'; 263 window.utmParams.utm_medium = 'cpc'; 264 window.utmParams.utm_campaign = 'bing_ads'; 265 } else if (urlParams.get('twclid')) { 266 window.utmParams.utm_source = 'twitter'; 267 window.utmParams.utm_medium = 'paid_social'; 268 window.utmParams.utm_campaign = 'twitter_ads'; 269 } else if (urlParams.get('sclid')) { 270 window.utmParams.utm_source = 'snapchat'; 271 window.utmParams.utm_medium = 'paid_social'; 272 window.utmParams.utm_campaign = 'snapchat_ads'; 273 } 274 } 275 276 // Detect in-app browsers and referrer-based sources when no UTMs present 277 if (!window.utmParams.utm_source) { 278 var ua = navigator.userAgent || ''; 279 var ref = document.referrer || ''; 280 if (/FBAN|FBAV|FB_IAB/i.test(ua)) { 281 window.utmParams.utm_source = 'facebook'; 282 window.utmParams.utm_medium = 'social'; 283 window.utmParams.utm_campaign = 'in_app_browser'; 284 } else if (/Instagram/i.test(ua)) { 285 window.utmParams.utm_source = 'instagram'; 286 window.utmParams.utm_medium = 'social'; 287 window.utmParams.utm_campaign = 'in_app_browser'; 288 } else if (/LinkedInApp/i.test(ua)) { 289 window.utmParams.utm_source = 'linkedin'; 290 window.utmParams.utm_medium = 'social'; 291 window.utmParams.utm_campaign = 'in_app_browser'; 292 } else if (/Twitter|TwitterAndroid/i.test(ua)) { 293 window.utmParams.utm_source = 'twitter'; 294 window.utmParams.utm_medium = 'social'; 295 window.utmParams.utm_campaign = 'in_app_browser'; 296 } else if (/Snapchat/i.test(ua)) { 297 window.utmParams.utm_source = 'snapchat'; 298 window.utmParams.utm_medium = 'social'; 299 window.utmParams.utm_campaign = 'in_app_browser'; 300 } else if (/TikTok/i.test(ua)) { 301 window.utmParams.utm_source = 'tiktok'; 302 window.utmParams.utm_medium = 'social'; 303 window.utmParams.utm_campaign = 'in_app_browser'; 304 } else if (/Pinterest/i.test(ua)) { 305 window.utmParams.utm_source = 'pinterest'; 306 window.utmParams.utm_medium = 'social'; 307 window.utmParams.utm_campaign = 'in_app_browser'; 308 } else if (/WhatsApp/i.test(ua)) { 309 window.utmParams.utm_source = 'whatsapp'; 310 window.utmParams.utm_medium = 'social'; 311 window.utmParams.utm_campaign = 'in_app_browser'; 312 } else if (/Telegram/i.test(ua)) {
313 window.utmParams.utm_source = 'telegram'; 314 window.utmParams.utm_medium = 'social'; 315 window.utmParams.utm_campaign = 'in_app_browser'; 316 } else if (/Discord/i.test(ua)) { 317 window.utmParams.utm_source = 'discord'; 318 window.utmParams.utm_medium = 'social'; 319 window.utmParams.utm_campaign = 'in_app_browser'; 320 } else if (/Slack/i.test(ua) && !/Slackbot/i.test(ua)) { 321 window.utmParams.utm_source = 'slack'; 322 window.utmParams.utm_medium = 'social'; 323 window.utmParams.utm_campaign = 'in_app_browser'; 324 } else if (/Reddit/i.test(ua)) { 325 window.utmParams.utm_source = 'reddit'; 326 window.utmParams.utm_medium = 'social'; 327 window.utmParams.utm_campaign = 'in_app_browser'; 328 } else if (/Threads/i.test(ua)) { 329 window.utmParams.utm_source = 'threads'; 330 window.utmParams.utm_medium = 'social'; 331 window.utmParams.utm_campaign = 'in_app_browser'; 332 } else if (/facebook\.com|fb\.com/i.test(ref)) { 333 window.utmParams.utm_source = 'facebook'; 334 window.utmParams.utm_medium = 'social'; 335 window.utmParams.utm_campaign = 'referrer'; 336 } else if (/instagram\.com/i.test(ref)) { 337 window.utmParams.utm_source = 'instagram'; 338 window.utmParams.utm_medium = 'social'; 339 window.utmParams.utm_campaign = 'referrer'; 340 } else if (/reddit\.com/i.test(ref)) { 341 window.utmParams.utm_source = 'reddit'; 342 window.utmParams.utm_medium = 'social'; 343 window.utmParams.utm_campaign = 'referrer'; 344 } else if (/twitter\.com|t\.co|x\.com/i.test(ref)) { 345 window.utmParams.utm_source = 'twitter'; 346 window.utmParams.utm_medium = 'social'; 347 window.utmParams.utm_campaign = 'referrer'; 348 } else if (/linkedin\.com/i.test(ref)) { 349 window.utmParams.utm_source = 'linkedin'; 350 window.utmParams.utm_medium = 'social'; 351 window.utmParams.utm_campaign = 'referrer'; 352 } else if (/pinterest\.com/i.test(ref)) { 353 window.utmParams.utm_source = 'pinterest'; 354 window.utmParams.utm_medium = 'social'; 355 window.utmParams.utm_campaign = 'referrer'; 356 } else if (/youtube\.com|youtu\.be/i.test(ref)) { 357 window.utmParams.utm_source = 'youtube'; 358 window.utmParams.utm_medium = 'social'; 359 window.utmParams.utm_campaign = 'referrer'; 360 } else if (/tiktok\.com/i.test(ref)) { 361 window.utmParams.utm_source = 'tiktok'; 362 window.utmParams.utm_medium = 'social'; 363 window.utmParams.utm_campaign = 'referrer'; 364 } else if (/google\./i.test(ref)) { 365 window.utmParams.utm_source = 'google'; 366 window.utmParams.utm_medium = 'organic'; 367 window.utmParams.utm_campaign = 'referrer'; 368 } else if (/bing\.com/i.test(ref)) { 369 window.utmParams.utm_source = 'bing'; 370 window.utmParams.utm_medium = 'organic'; 371 window.utmParams.utm_campaign = 'referrer'; 372 } else if (/yahoo\.com/i.test(ref)) { 373 window.utmParams.utm_source = 'yahoo'; 374 window.utmParams.utm_medium = 'organic'; 375 window.utmParams.utm_campaign = 'referrer'; 376 } else if (/duckduckgo\.com/i.test(ref)) { 377 window.utmParams.utm_source = 'duckduckgo'; 378 window.utmParams.utm_medium = 'organic'; 379 window.utmParams.utm_campaign = 'referrer'; 380 } else if (ref && ref.indexOf(window.location.hostname) === -1 && ref.indexOf('offa.com') === -1) { 381 try { 382 window.utmParams.utm_source = new URL(ref).hostname.replace('www.', ''); 383 window.utmParams.utm_medium = 'referral'; 384 window.utmParams.utm_campaign = 'referrer'; 385 } catch(e) {} 386 } 387 } 388 389 if (window.utmParams.utm_source) { 390 sessionStorage.setItem('landing_utm_params', JSON.stringify(window.utmParams)); 391 } 392 393 // Helper: initialize Amplitude and fire page view 394 function initAmplitudeAuth() { 395 if (!window.amplitude) return; 396 try { 397 // Cross-domain identity merge: if user came from grade.offa.com, 398 // use their device_id so both sessions appear as one user timeline
399 var graderDeviceId = urlParams.get('amp_device_id'); 400 if (graderDeviceId) { 401 window.amplitude.setDeviceId(graderDeviceId); 402 } 403 404 window.amplitude.init('fb0b21686a91e254311b9a32af79274b', { 405 serverUrl: '/amp/api/2/httpapi', 406 autocapture: { 407 elementInteractions: false, 408 fileDownloads: false, 409 formInteractions: false, 410 pageViews: false, 411 sessions: true, 412 attribution: true 413 } 414 }); 415 416 // Set UTM user properties for channel attribution 417 try { 418 if (window.utmParams && window.utmParams.utm_source) { 419 var identifyEvent = new window.amplitude.Identify(); 420 // First-touch (initial) - for "where did they originally come from" 421 if (window.utmParams.utm_source) identifyEvent.setOnce('initial_utm_source', window.utmParams.utm_source); 422 if (window.utmParams.utm_medium) identifyEvent.setOnce('initial_utm_medium', window.utmParams.utm_medium); 423 if (window.utmParams.utm_campaign) identifyEvent.setOnce('initial_utm_campaign', window.utmParams.utm_campaign); 424 if (window.utmParams.utm_content) identifyEvent.setOnce('initial_utm_content', window.utmParams.utm_content); 425 if (window.utmParams.utm_term) identifyEvent.setOnce('initial_utm_term', window.utmParams.utm_term); 426 // Last-touch (standard) - for Channel Classifier 427 if (window.utmParams.utm_source) identifyEvent.set('utm_source', window.utmParams.utm_source); 428 if (window.utmParams.utm_medium) identifyEvent.set('utm_medium', window.utmParams.utm_medium); 429 if (window.utmParams.utm_campaign) identifyEvent.set('utm_campaign', window.utmParams.utm_campaign); 430 if (window.utmParams.utm_content) identifyEvent.set('utm_content', window.utmParams.utm_content); 431 if (window.utmParams.utm_term) identifyEvent.set('utm_term', window.utmParams.utm_term); 432 window.amplitude.identify(identifyEvent); 433 } 434 if (document.referrer && document.referrer.indexOf('offa.com') === -1 && document.referrer.indexOf(window.location.hostname) === -1) { 435 var refIdentify = new window.amplitude.Identify(); 436 refIdentify.setOnce('initial_referrer', document.referrer); 437 refIdentify.set('referrer', document.referrer); 438 window.amplitude.identify(refIdentify); 439 } 440 } catch (e) { 441 console.warn('Amplitude UTM identify failed:', e); 442 } 443 444 var screenName = window._screenName || 'auth'; 445 window.amplitude.track(screenName + '_view', { 446 page_url: window.location.href, 447 page_path: window.location.pathname, 448 page_title: document.title, 449 screen_name: screenName, 450 referrer: document.referrer || null, 451 screen_width: window.innerWidth, 452 screen_height: window.innerHeight, 453 platform: 'web', 454 timestamp: new Date().toISOString(), 455 user_id: null, 456 user_phone: null, 457 user_email: null, 458 is_authenticated: false, 459 utm_source: window.utmParams.utm_source, 460 utm_medium: window.utmParams.utm_medium, 461 utm_campaign: window.utmParams.utm_campaign, 462 utm_content: window.utmParams.utm_content, 463 utm_term: window.utmParams.utm_term 464 }); 465 } catch (e) { 466 console.warn('Amplitude init failed:', e); 467 } 468 } 469 470 // 1. Load core Amplitude SDK (via first-party proxy to bypass ad blockers) 471 var amplitudeScript = document.createElement('script'); 472 amplitudeScript.src = '/amp/sdk.js'; 473 amplitudeScript.onerror = function() { 474 // Fallback to CDN if proxy fails 475 var fallback = document.createElement('script'); 476 fallback.src = 'https://cdn.amplitude.com/libs/analytics-browser-2.22.0-min.js.gz'; 477 fallback.onload = function() { loadReplayAuth(); }; 478 fallback.onerror = function() { console.warn('Amplitude SDK failed to load'); }; 479 document.head.appendChild(fallback); 480 }; 481 amplitudeScript.onload = function() { loadReplayAuth(); }; 482 483 function loadReplayAuth() { 484 var replayScript = document.createElement('script'); 485 replayScript.src = '/amp/replay.js'; 486 replayScript.onload = function() { 487 try { 488 if (window.amplitude && window.sessionReplay) { 489 window.amplitude.add(window.sessionReplay.plugin({ 490 sampleRate: 1, 491 useWebWorker: true 492 })); 493 } 494 } catch (e) { 495 console.warn('Amplitude session replay plugin failed:', e); 496 } 497 initAmplitudeAuth(); 498 }; 499 replayScript.onerror = function() { 500 console.warn('Session replay script failed to load, continuing without it'); 501 initAmplitudeAuth(); 502 }; 503 document.head.appendChild(replayScript); 504 } 505 506 document.head.appendChild(amplitudeScript); 507 })(); 508 </script>
508 509
510<script> 511 function formatPhoneNumber(input) { 512 let digits = input.value.replace(/\D/g, ''); 513 if (digits.length > 10) digits = digits.slice(0, 10); 514 515 let formatted = ''; 516 if (digits.length > 6) { 517 formatted = digits.replace(/(\d{3})(\d{3})(\d{1,4})/, '$1-$2-$3'); 518 } else if (digits.length > 3) { 519 formatted = digits.replace(/(\d{3})(\d{1,3})/, '$1-$2'); 520 } else { 521 formatted = digits; 522 } 523 input.value = formatted; 524 } 525 526 document.addEventListener('DOMContentLoaded', function() { 527 const toggleBtn = document.getElementById('toggle-method'); 528 const phoneGroup = document.getElementById('phone-input-group'); 529 const emailGroup = document.getElementById('email-input-group'); 530 const phoneInput = document.getElementById('phone'); 531 const emailInput = document.getElementById('email'); 532 533 if (toggleBtn) { 534 toggleBtn.addEventListener('click', function(e) { 535 e.preventDefault(); 536 537 const switchingToEmail = !phoneGroup.classList.contains('hidden'); 538 539 if (phoneGroup.classList.contains('hidden')) { 540 phoneGroup.classList.remove('hidden'); 541 emailGroup.classList.add('hidden'); 542 phoneInput.value = ''; 543 emailInput.value = ''; 544 toggleBtn.textContent = 'Use Email instead'; 545 } else { 546 phoneGroup.classList.add('hidden'); 547 emailGroup.classList.remove('hidden'); 548 phoneInput.value = ''; 549 emailInput.value = ''; 550 toggleBtn.textContent = 'Use Phone instead'; 551 } 552 553 // Track method toggle 554 if (window.amplitude) { 555 window.amplitude.track('unified_auth_method_toggled', { 556 switched_to: switchingToEmail ? 'email' : 'phone' 557 }); 558 } 559 }); 560 } 561 562 // Country code selector 563 const countrySelect = document.getElementById('country-code'); 564 if (countrySelect) { 565 countrySelect.addEventListener('change', function() { 566 const selectedOption = this.options[this.selectedIndex]; 567 if (!selectedOption) return; 568 const flagCode = selectedOption.getAttribute('data-flag'); 569 document.getElementById('flag-display').className = `fi fi-${flagCode}`; 570 document.getElementById('code-display').textContent = selectedOption.value; 571 }); 572 } 573 574 // Track form submission 575 const authForm = document.getElementById('authForm'); 576 if (authForm) { 577 authForm.addEventListener('submit', function() { 578 const method = phoneGroup.classList.contains('hidden') ? 'email' : 'phone'; 579 if (window.amplitude) { 580 window.amplitude.track('unified_auth_submitted', { 581 auth_method: method 582 }); 583 } 584 }); 585 } 586 }); 587</script>
587 588 589 590 <!-- Global UTM Share Utility (for auth pages) --> 591
591<script> 592 if (!window.appendShareUtm) { 593 window.appendShareUtm = function(url, platform) { 594 try { 595 var urlObj = new URL(url, window.location.origin); 596 urlObj.searchParams.delete('ref'); 597 urlObj.searchParams.delete('debug_amplitude'); 598 urlObj.searchParams.delete('show_welcome'); 599 urlObj.searchParams.delete('map_lat'); 600 urlObj.searchParams.delete('map_lng'); 601 urlObj.searchParams.delete('map_zoom'); 602 if (urlObj.searchParams.has('utm_source')) return urlObj.toString(); 603 var source = 'offa', medium = 'referral', campaign = 'property_share'; 604 if (platform) { 605 var p = platform.toLowerCase(); 606 if (p === 'facebook') { source = 'facebook'; medium = 'social'; } 607 else if (p === 'instagram') { source = 'instagram'; medium = 'social'; } 608 else if (p === 'tiktok') { source = 'tiktok'; medium = 'social'; } 609 else if (p === 'youtube') { source = 'youtube'; medium = 'social'; } 610 else if (p === 'twitter' || p === 'x') { source = 'twitter'; medium = 'social'; } 611 else if (p === 'reddit') { source = 'reddit'; medium = 'social'; } 612 else if (p === 'whatsapp') { source = 'whatsapp'; medium = 'social'; } 613 else if (p === 'copy' || p === 'native_share') { source = 'offa'; medium = 'referral'; } 614 else if (p === 'sms' || p === 'text') { source = 'sms'; medium = 'social'; } 615 else if (p === 'email') { source = 'email'; medium = 'email'; } 616 else { source = p; medium = 'social'; } 617 } 618 urlObj.searchParams.set('utm_source', source); 619 urlObj.searchParams.set('utm_medium', medium); 620 urlObj.searchParams.set('utm_campaign', campaign); 621 return urlObj.toString(); 622 } catch (e) { return url; } 623 }; 624 } 625 </script>
625 626</body> 627</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.