[{"data":1,"prerenderedAt":1453},["ShallowReactive",2],{"docsv3-nav":3,"\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-mobile":236},[4],{"title":5,"path":6,"stem":7,"children":8,"page":188},"V3","\u002Fdocs\u002Fv3","1.docs\u002Fv3",[9,13,17,21,38,87,189,198,219],{"title":10,"path":11,"stem":12},"Introduction","\u002Fdocs\u002Fv3\u002Fintroduction","1.docs\u002Fv3\u002F1.Introduction",{"title":14,"path":15,"stem":16},"Quick start","\u002Fdocs\u002Fv3\u002Fquick-start","1.docs\u002Fv3\u002F2.Quick start",{"title":18,"path":19,"stem":20},"Challenge flow","\u002Fdocs\u002Fv3\u002Fchallenge-flow","1.docs\u002Fv3\u002F3.Challenge flow",{"title":22,"path":23,"stem":24,"children":25},"Fundamentals","\u002Fdocs\u002Fv3\u002Ffundamentals","1.docs\u002Fv3\u002F4.fundamentals",[26,30,34],{"title":27,"path":28,"stem":29},"Signup protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Fsignup-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F00.Signup protection",{"title":31,"path":32,"stem":33},"Login protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Flogin-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F01.Login protection",{"title":35,"path":36,"stem":37},"Access protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Faccess-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F02.Access protection",{"title":39,"path":40,"stem":41,"children":42},"Guides","\u002Fdocs\u002Fv3\u002Fguides","1.docs\u002Fv3\u002F5.guides",[43,47,51,55,59,63,67,71,75,79,83],{"title":44,"path":45,"stem":46},"Account sharing prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-sharing-prevention","1.docs\u002Fv3\u002F5.guides\u002F1.Account sharing prevention",{"title":48,"path":49,"stem":50},"Web scraping prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fweb-scraping-prevention","1.docs\u002Fv3\u002F5.guides\u002F13.Web scraping prevention",{"title":52,"path":53,"stem":54},"Ban enforcement","\u002Fdocs\u002Fv3\u002Fguides\u002Fban-enforcement","1.docs\u002Fv3\u002F5.guides\u002F14.Ban enforcement",{"title":56,"path":57,"stem":58},"Chargeback dispute","\u002Fdocs\u002Fv3\u002Fguides\u002Fchargeback-dispute","1.docs\u002Fv3\u002F5.guides\u002F15.Chargeback dispute",{"title":60,"path":61,"stem":62},"Multi-accounting prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fmulti-accounting-prevention","1.docs\u002Fv3\u002F5.guides\u002F16.Multi-accounting prevention",{"title":64,"path":65,"stem":66},"Account takeover prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-takeover-prevention","1.docs\u002Fv3\u002F5.guides\u002F2.Account takeover prevention",{"title":68,"path":69,"stem":70},"Risky transaction prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Frisky-transaction-prevention","1.docs\u002Fv3\u002F5.guides\u002F20.Risky transaction prevention",{"title":72,"path":73,"stem":74},"Fake account detection","\u002Fdocs\u002Fv3\u002Fguides\u002Ffake-account-detection","1.docs\u002Fv3\u002F5.guides\u002F3.Fake account detection",{"title":76,"path":77,"stem":78},"Bot detection","\u002Fdocs\u002Fv3\u002Fguides\u002Fbot-detection","1.docs\u002Fv3\u002F5.guides\u002F4.Bot detection",{"title":80,"path":81,"stem":82},"Card testing prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fcard-testing-prevention","1.docs\u002Fv3\u002F5.guides\u002F5.Card testing prevention",{"title":84,"path":85,"stem":86},"Incentive abuse prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fincentive-abuse-prevention","1.docs\u002Fv3\u002F5.guides\u002F9.Incentive abuse prevention",{"title":88,"path":89,"stem":90,"children":91,"page":188},"Concepts","\u002Fdocs\u002Fv3\u002Fconcepts","1.docs\u002Fv3\u002F6.concepts",[92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184],{"title":93,"path":94,"stem":95},"Evaluations","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fevaluations","1.docs\u002Fv3\u002F6.concepts\u002F01.evaluations",{"title":97,"path":98,"stem":99},"Actions","\u002Fdocs\u002Fv3\u002Fconcepts\u002Factions","1.docs\u002Fv3\u002F6.concepts\u002F02.actions",{"title":101,"path":102,"stem":103},"Signals","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fsignals","1.docs\u002Fv3\u002F6.concepts\u002F03.signals",{"title":105,"path":106,"stem":107},"Checks","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchecks","1.docs\u002Fv3\u002F6.concepts\u002F04.checks",{"title":109,"path":110,"stem":111},"Risks","\u002Fdocs\u002Fv3\u002Fconcepts\u002Frisks","1.docs\u002Fv3\u002F6.concepts\u002F05.risks",{"title":113,"path":114,"stem":115},"Verdicts","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fverdicts","1.docs\u002Fv3\u002F6.concepts\u002F06.verdicts",{"title":117,"path":118,"stem":119},"Policies","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fpolicies","1.docs\u002Fv3\u002F6.concepts\u002F07.policies",{"title":121,"path":122,"stem":123},"Challenges","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchallenges","1.docs\u002Fv3\u002F6.concepts\u002F08.challenges",{"title":125,"path":126,"stem":127},"Concurrency","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fconcurrency","1.docs\u002Fv3\u002F6.concepts\u002F09.concurrency",{"title":129,"path":130,"stem":131},"Impossible travel","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fimpossible-travel","1.docs\u002Fv3\u002F6.concepts\u002F10.impossible-travel",{"title":133,"path":134,"stem":135},"Bots","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fbots","1.docs\u002Fv3\u002F6.concepts\u002F11.bots",{"title":137,"path":138,"stem":139},"Devices","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fdevices","1.docs\u002Fv3\u002F6.concepts\u002F12.devices",{"title":141,"path":142,"stem":143},"Fingerprints","\u002Fdocs\u002Fv3\u002Fconcepts\u002Ffingerprints","1.docs\u002Fv3\u002F6.concepts\u002F13.fingerprints",{"title":145,"path":146,"stem":147},"People","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fpeople","1.docs\u002Fv3\u002F6.concepts\u002F14.people",{"title":149,"path":150,"stem":151},"Lists","\u002Fdocs\u002Fv3\u002Fconcepts\u002Flists","1.docs\u002Fv3\u002F6.concepts\u002F15.lists",{"title":153,"path":154,"stem":155},"Account takeover","\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-takeover","1.docs\u002Fv3\u002F6.concepts\u002F16.account-takeover",{"title":157,"path":158,"stem":159},"Account sharing","\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-sharing","1.docs\u002Fv3\u002F6.concepts\u002F17.account-sharing",{"title":161,"path":162,"stem":163},"Fake account","\u002Fdocs\u002Fv3\u002Fconcepts\u002Ffake-account","1.docs\u002Fv3\u002F6.concepts\u002F18.fake-account",{"title":165,"path":166,"stem":167},"Scraping","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fscraping","1.docs\u002Fv3\u002F6.concepts\u002F19.scraping",{"title":169,"path":170,"stem":171},"Linked accounts","\u002Fdocs\u002Fv3\u002Fconcepts\u002Flinked-accounts","1.docs\u002Fv3\u002F6.concepts\u002F20.linked-accounts",{"title":173,"path":174,"stem":175},"New IP","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fip","1.docs\u002Fv3\u002F6.concepts\u002F21.ip",{"title":177,"path":178,"stem":179},"Anonymizing network","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fanonymizing-network","1.docs\u002Fv3\u002F6.concepts\u002F22.anonymizing-network",{"title":181,"path":182,"stem":183},"Email quality","\u002Fdocs\u002Fv3\u002Fconcepts\u002Femail","1.docs\u002Fv3\u002F6.concepts\u002F23.email",{"title":185,"path":186,"stem":187},"Velocity","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fvelocity","1.docs\u002Fv3\u002F6.concepts\u002F24.velocity",false,{"title":190,"path":191,"stem":192,"children":193,"page":188},"Advanced","\u002Fdocs\u002Fv3\u002Fadvanced","1.docs\u002Fv3\u002F7.Advanced",[194],{"title":195,"path":196,"stem":197},"Proxy setup","\u002Fdocs\u002Fv3\u002Fadvanced\u002Fproxy-setup","1.docs\u002Fv3\u002F7.Advanced\u002F1.Proxy-setup",{"title":199,"path":200,"stem":201,"children":202},"Integrations","\u002Fdocs\u002Fv3\u002Fintegrations","1.docs\u002Fv3\u002F8.integrations",[203,207,211,215],{"title":204,"path":205,"stem":206},"Kajabi","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fkajabi-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F1.Kajabi account sharing prevention",{"title":208,"path":209,"stem":210},"Teachable","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fteachable-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F2.Teachable account sharing prevention",{"title":212,"path":213,"stem":214},"Thinkific","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fthinkific-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F3.Thinkific account sharing prevention",{"title":216,"path":217,"stem":218},"LearnWorlds","\u002Fdocs\u002Fv3\u002Fintegrations\u002Flearnworlds-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F4.LearnWorlds account sharing prevention",{"title":220,"path":221,"stem":222,"children":223,"page":188},"Migration","\u002Fdocs\u002Fv3\u002Fmigration","1.docs\u002Fv3\u002F9.migration",[224,228,232],{"title":225,"path":226,"stem":227},"Overview","\u002Fdocs\u002Fv3\u002Fmigration\u002Foverview","1.docs\u002Fv3\u002F9.migration\u002F1.Overview",{"title":229,"path":230,"stem":231},"Account sharing on web","\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web","1.docs\u002Fv3\u002F9.migration\u002F2.Account sharing on web",{"title":233,"path":234,"stem":235},"Account sharing on mobile","\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-mobile","1.docs\u002Fv3\u002F9.migration\u002F3.Account sharing on mobile",{"id":237,"title":233,"body":238,"description":1447,"extension":1448,"meta":1449,"navigation":548,"path":234,"rawbody":1450,"seo":1451,"stem":235,"__hash__":1452},"docsv3\u002F1.docs\u002Fv3\u002F9.migration\u002F3.Account sharing on mobile.md",{"type":239,"value":240,"toc":1430},"minimark",[241,246,268,318,325,330,335,342,346,490,636,655,659,662,695,702,706,852,856,860,863,907,914,917,931,1001,1134,1147,1150,1189,1200,1204,1324,1328,1331,1388,1396,1400,1410,1414,1426],[242,243,245],"h1",{"id":244},"account-sharing-on-ios-and-android","Account sharing on iOS and Android",[247,248,249,250,254,255,259,260,263,264,267],"p",{},"The shift is the same as ",[251,252,253],"a",{"href":230},"on web",": ",[256,257,258],"code",{},"attach"," becomes ",[256,261,262],{},"evaluate"," with the ",[256,265,266],{},"access"," action. The bigger change on mobile is how challenges are shown and which callbacks exist. Three changes apply on both platforms:",[269,270,271,294,312],"ol",{},[272,273,274,278,279,281,282,285,286,289,290,293],"li",{},[275,276,277],"strong",{},"One entry point."," Configuring the client, setting the user, and attaching collapse into a single ",[256,280,262],{}," call that takes ",[256,283,284],{},"user",", ",[256,287,288],{},"email",", and ",[256,291,292],{},"phone"," inline.",[272,295,296,299,300,303,304,307,308,311],{},[275,297,298],{},"Challenges render through a container."," You add ",[256,301,302],{},"RuptContainerView"," (iOS) or ",[256,305,306],{},"RuptContainer"," (Android) to your UI and it observes ",[256,309,310],{},"redirectURL",". The SDK no longer pushes its own view controller or activity, so the \"should present\" hooks are gone.",[272,313,314,317],{},[275,315,316],{},"The callback set is smaller."," The device-limit and pre-challenge callbacks are dropped, and two challenge-button callbacks are added.",[319,320,322],"alert",{"type":321},"warning",[247,323,324],{},"This is a breaking upgrade. Every app needs code changes, and there is no compatibility shim. The steps below are the full swap.",[326,327,329],"h2",{"id":328},"ios-381-to-400","iOS (3.8.1 to 4.0.0)",[331,332,334],"h3",{"id":333},"step-1-replace-the-framework","Step 1: Replace the framework",[247,336,337,338,341],{},"Download the new ",[256,339,340],{},"RuptClient.xcframework"," and replace the old binary in your project.",[331,343,345],{"id":344},"step-2-create-the-client-then-evaluate","Step 2: Create the client, then evaluate",[347,348,353],"pre",{"className":349,"code":350,"language":351,"meta":352,"style":352},"language-swift shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F v2\nlet rupt = Rupt(clientID: \"your_client_id\", useViewController: true)\nrupt.onLogoutCurrentDevice = {\n    \u002F\u002F Clear your session and sign the user out locally.\n}\nrupt.setUserID(user.id)\nrupt.setEmail(user.email)\nrupt.attach()\n","swift","",[256,354,355,364,418,434,440,446,464,480],{"__ignoreMap":352},[356,357,360],"span",{"class":358,"line":359},"line",1,[356,361,363],{"class":362},"s42Qa","\u002F\u002F v2\n",[356,365,367,371,375,379,383,387,390,393,397,401,404,406,409,411,415],{"class":358,"line":366},2,[356,368,370],{"class":369},"s2NTT","let",[356,372,374],{"class":373},"sJCYa"," rupt ",[356,376,378],{"class":377},"sKfv_","=",[356,380,382],{"class":381},"sh6BQ"," Rupt",[356,384,386],{"class":385},"shEKG","(",[356,388,389],{"class":381},"clientID",[356,391,392],{"class":385},":",[356,394,396],{"class":395},"s9QZx"," \"",[356,398,400],{"class":399},"siibJ","your_client_id",[356,402,403],{"class":395},"\"",[356,405,285],{"class":373},[356,407,408],{"class":381},"useViewController",[356,410,392],{"class":385},[356,412,414],{"class":413},"s4fYk"," true",[356,416,417],{"class":385},")\n",[356,419,421,424,428,431],{"class":358,"line":420},3,[356,422,423],{"class":373},"rupt.",[356,425,427],{"class":426},"seeE2","onLogoutCurrentDevice",[356,429,430],{"class":377}," =",[356,432,433],{"class":385}," {\n",[356,435,437],{"class":358,"line":436},4,[356,438,439],{"class":362},"    \u002F\u002F Clear your session and sign the user out locally.\n",[356,441,443],{"class":358,"line":442},5,[356,444,445],{"class":385},"}\n",[356,447,449,451,454,456,459,462],{"class":358,"line":448},6,[356,450,423],{"class":373},[356,452,453],{"class":381},"setUserID",[356,455,386],{"class":385},[356,457,458],{"class":373},"user.",[356,460,461],{"class":426},"id",[356,463,417],{"class":385},[356,465,467,469,472,474,476,478],{"class":358,"line":466},7,[356,468,423],{"class":373},[356,470,471],{"class":381},"setEmail",[356,473,386],{"class":385},[356,475,458],{"class":373},[356,477,288],{"class":426},[356,479,417],{"class":385},[356,481,483,485,487],{"class":358,"line":482},8,[356,484,423],{"class":373},[356,486,258],{"class":381},[356,488,489],{"class":385},"()\n",[347,491,493],{"className":349,"code":492,"language":351,"meta":352,"style":352},"\u002F\u002F v4\nlet rupt = Rupt(clientID: \"your_client_id\")\nrupt.onLogout = {\n    \u002F\u002F Fires when this session is logged out remotely. Clear your local session.\n}\n\n\u002F\u002F Same call site as attach: once per protected screen, for paying users.\ntry await rupt.evaluate(\n    action: \"access\",\n    user: user.id,\n    email: user.email,\n    phone: user.phone\n)\n",[256,494,495,500,524,535,540,544,550,555,572,589,604,618,631],{"__ignoreMap":352},[356,496,497],{"class":358,"line":359},[356,498,499],{"class":362},"\u002F\u002F v4\n",[356,501,502,504,506,508,510,512,514,516,518,520,522],{"class":358,"line":366},[356,503,370],{"class":369},[356,505,374],{"class":373},[356,507,378],{"class":377},[356,509,382],{"class":381},[356,511,386],{"class":385},[356,513,389],{"class":381},[356,515,392],{"class":385},[356,517,396],{"class":395},[356,519,400],{"class":399},[356,521,403],{"class":395},[356,523,417],{"class":385},[356,525,526,528,531,533],{"class":358,"line":420},[356,527,423],{"class":373},[356,529,530],{"class":426},"onLogout",[356,532,430],{"class":377},[356,534,433],{"class":385},[356,536,537],{"class":358,"line":436},[356,538,539],{"class":362},"    \u002F\u002F Fires when this session is logged out remotely. Clear your local session.\n",[356,541,542],{"class":358,"line":442},[356,543,445],{"class":385},[356,545,546],{"class":358,"line":448},[356,547,549],{"emptyLinePlaceholder":548},true,"\n",[356,551,552],{"class":358,"line":466},[356,553,554],{"class":362},"\u002F\u002F Same call site as attach: once per protected screen, for paying users.\n",[356,556,557,561,564,567,569],{"class":358,"line":482},[356,558,560],{"class":559},"sAPXc","try",[356,562,563],{"class":559}," await",[356,565,566],{"class":373}," rupt.",[356,568,262],{"class":381},[356,570,571],{"class":385},"(\n",[356,573,575,578,580,582,584,586],{"class":358,"line":574},9,[356,576,577],{"class":381},"    action",[356,579,392],{"class":385},[356,581,396],{"class":395},[356,583,266],{"class":399},[356,585,403],{"class":395},[356,587,588],{"class":373},",\n",[356,590,592,595,597,600,602],{"class":358,"line":591},10,[356,593,594],{"class":381},"    user",[356,596,392],{"class":385},[356,598,599],{"class":373}," user.",[356,601,461],{"class":426},[356,603,588],{"class":373},[356,605,607,610,612,614,616],{"class":358,"line":606},11,[356,608,609],{"class":381},"    email",[356,611,392],{"class":385},[356,613,599],{"class":373},[356,615,288],{"class":426},[356,617,588],{"class":373},[356,619,621,624,626,628],{"class":358,"line":620},12,[356,622,623],{"class":381},"    phone",[356,625,392],{"class":385},[356,627,599],{"class":373},[356,629,630],{"class":426},"phone\n",[356,632,634],{"class":358,"line":633},13,[356,635,417],{"class":385},[247,637,638,285,640,285,642,285,645,289,648,651,652,654],{},[256,639,453],{},[256,641,471],{},[256,643,644],{},"setPhone",[256,646,647],{},"identify",[256,649,650],{},"getHash"," are gone. Pass the user inline to ",[256,653,262],{}," instead.",[331,656,658],{"id":657},"step-3-show-challenges-through-the-container","Step 3: Show challenges through the container",[247,660,661],{},"Wrap your root view so the challenge can overlay it:",[347,663,665],{"className":349,"code":664,"language":351,"meta":352,"style":352},"RuptContainerView(rupt: rupt) {\n    \u002F\u002F your app content\n}\n",[256,666,667,686,691],{"__ignoreMap":352},[356,668,669,671,673,676,678,681,684],{"class":358,"line":359},[356,670,302],{"class":381},[356,672,386],{"class":385},[356,674,675],{"class":381},"rupt",[356,677,392],{"class":385},[356,679,680],{"class":373}," rupt",[356,682,683],{"class":385},")",[356,685,433],{"class":385},[356,687,688],{"class":358,"line":366},[356,689,690],{"class":362},"    \u002F\u002F your app content\n",[356,692,693],{"class":358,"line":420},[356,694,445],{"class":385},[247,696,697,698,701],{},"UIKit hosts skip the container, observe ",[256,699,700],{},"$redirectURL",", and present the challenge web view themselves.",[331,703,705],{"id":704},"ios-events","iOS events",[707,708,709,725],"table",{},[710,711,712],"thead",{},[713,714,715,719,722],"tr",{},[716,717,718],"th",{},"v2 (3.8.1)",[716,720,721],{},"v4 (4.0.0)",[716,723,724],{},"What changed",[726,727,728,742,756,770,787,801,813,827,840],"tbody",{},[713,729,730,735,739],{},[731,732,733],"td",{},[256,734,427],{},[731,736,737],{},[256,738,530],{},[731,740,741],{},"Renamed",[713,743,744,749,754],{},[731,745,746],{},[256,747,748],{},"onChallengeCompleted",[731,750,751],{},[256,752,753],{},"onComplete",[731,755,741],{},[713,757,758,763,767],{},[731,759,760],{},[256,761,762],{},"onBackButtonPressed",[731,764,765],{},[256,766,762],{},[731,768,769],{},"Unchanged",[713,771,772,777,780],{},[731,773,774],{},[256,775,776],{},"onLimitExceeded",[731,778,779],{},"Removed",[731,781,782,783,786],{},"Cap devices with a ",[256,784,785],{},"device_count"," policy",[713,788,789,794,796],{},[731,790,791],{},[256,792,793],{},"onChallenge",[731,795,779],{},[731,797,798,799],{},"The SDK surfaces the challenge via ",[256,800,310],{},[713,802,803,808,810],{},[731,804,805],{},[256,806,807],{},"onCreateNewAccount",[731,809,779],{},[731,811,812],{},"Conversion is handled by the challenge Success URL",[713,814,815,820,822],{},[731,816,817],{},[256,818,819],{},"shouldPresentChallengeViewController",[731,821,779],{},[731,823,824,825],{},"Use ",[256,826,302],{},[713,828,829,832,837],{},[731,830,831],{},"Added",[731,833,834],{},[256,835,836],{},"onPrimaryCta",[731,838,839],{},"Fires when the challenge primary button is tapped",[713,841,842,844,849],{},[731,843,831],{},[731,845,846],{},[256,847,848],{},"onSecondaryCta",[731,850,851],{},"Fires when the challenge secondary button is tapped",[326,853,855],{"id":854},"android-210-to-400","Android (2.1.0 to 4.0.0)",[331,857,859],{"id":858},"step-1-swap-the-dependency","Step 1: Swap the dependency",[247,861,862],{},"Move from JitPack to Maven Central:",[347,864,868],{"className":865,"code":866,"language":867,"meta":352,"style":352},"language-groovy shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F v2\nimplementation 'com.github.getrupt:kotlin:2.1.0'\n\n\u002F\u002F v4\nimplementation 'dev.rupt.android:rupt-android:4.0.0'\n","groovy",[256,869,870,874,888,892,896],{"__ignoreMap":352},[356,871,872],{"class":358,"line":359},[356,873,363],{"class":362},[356,875,876,879,882,885],{"class":358,"line":366},[356,877,878],{"class":373},"implementation ",[356,880,881],{"class":395},"'",[356,883,884],{"class":399},"com.github.getrupt:kotlin:2.1.0",[356,886,887],{"class":395},"'\n",[356,889,890],{"class":358,"line":420},[356,891,549],{"emptyLinePlaceholder":548},[356,893,894],{"class":358,"line":436},[356,895,499],{"class":362},[356,897,898,900,902,905],{"class":358,"line":442},[356,899,878],{"class":373},[356,901,881],{"class":395},[356,903,904],{"class":399},"dev.rupt.android:rupt-android:4.0.0",[356,906,887],{"class":395},[247,908,909,910,913],{},"Make sure ",[256,911,912],{},"mavenCentral()"," is in your repositories.",[331,915,345],{"id":916},"step-2-create-the-client-then-evaluate-1",[247,918,919,920,923,924,926,927,930],{},"v2 was a ",[256,921,922],{},"configure"," plus ",[256,925,258],{}," on the ",[256,928,929],{},"Rupt"," singleton. v4 is an instance you create with your client ID.",[347,932,936],{"className":933,"code":934,"language":935,"meta":352,"style":352},"language-kotlin shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F v2\nRupt.configure(clientId = \"your_client_id\", account = user.id)\nRupt.onLogoutCurrentDevice = {\n    \u002F\u002F Clear your session and sign the user out locally.\n}\nRupt.attach(context = this)\n","kotlin",[256,937,938,942,967,976,980,984],{"__ignoreMap":352},[356,939,940],{"class":358,"line":359},[356,941,363],{"class":362},[356,943,944,947,950,953,956,959,962,964],{"class":358,"line":366},[356,945,946],{"class":373},"Rupt.",[356,948,922],{"class":949},"sjp9t",[356,951,952],{"class":373},"(clientId ",[356,954,378],{"class":955},"sut_7",[356,957,958],{"class":399}," \"your_client_id\"",[356,960,961],{"class":373},", account ",[356,963,378],{"class":955},[356,965,966],{"class":373}," user.id)\n",[356,968,969,972,974],{"class":358,"line":420},[356,970,971],{"class":373},"Rupt.onLogoutCurrentDevice ",[356,973,378],{"class":955},[356,975,433],{"class":373},[356,977,978],{"class":358,"line":436},[356,979,439],{"class":362},[356,981,982],{"class":358,"line":442},[356,983,445],{"class":373},[356,985,986,988,990,993,995,999],{"class":358,"line":448},[356,987,946],{"class":373},[356,989,258],{"class":949},[356,991,992],{"class":373},"(context ",[356,994,378],{"class":955},[356,996,998],{"class":997},"sDahn"," this",[356,1000,417],{"class":373},[347,1002,1004],{"className":933,"code":1003,"language":935,"meta":352,"style":352},"\u002F\u002F v4\nval rupt = Rupt(context = this, clientId = \"your_client_id\")\nrupt.onLogout = {\n    \u002F\u002F Fires when this session is logged out remotely. Clear your local session.\n}\n\n\u002F\u002F Same call site as attach: once per protected screen, for paying users.\nlifecycleScope.launch {\n    rupt.evaluate(\n        action = \"access\",\n        user = user.id,\n        email = user.email,\n        phone = user.phone,\n    )\n}\n",[256,1005,1006,1010,1037,1046,1050,1054,1058,1062,1072,1081,1093,1103,1113,1123,1129],{"__ignoreMap":352},[356,1007,1008],{"class":358,"line":359},[356,1009,499],{"class":362},[356,1011,1012,1016,1018,1020,1022,1024,1026,1028,1031,1033,1035],{"class":358,"line":366},[356,1013,1015],{"class":1014},"srTuz","val",[356,1017,374],{"class":373},[356,1019,378],{"class":955},[356,1021,382],{"class":949},[356,1023,992],{"class":373},[356,1025,378],{"class":955},[356,1027,998],{"class":997},[356,1029,1030],{"class":373},", clientId ",[356,1032,378],{"class":955},[356,1034,958],{"class":399},[356,1036,417],{"class":373},[356,1038,1039,1042,1044],{"class":358,"line":420},[356,1040,1041],{"class":373},"rupt.onLogout ",[356,1043,378],{"class":955},[356,1045,433],{"class":373},[356,1047,1048],{"class":358,"line":436},[356,1049,539],{"class":362},[356,1051,1052],{"class":358,"line":442},[356,1053,445],{"class":373},[356,1055,1056],{"class":358,"line":448},[356,1057,549],{"emptyLinePlaceholder":548},[356,1059,1060],{"class":358,"line":466},[356,1061,554],{"class":362},[356,1063,1064,1067,1070],{"class":358,"line":482},[356,1065,1066],{"class":373},"lifecycleScope.",[356,1068,1069],{"class":949},"launch",[356,1071,433],{"class":373},[356,1073,1074,1077,1079],{"class":358,"line":574},[356,1075,1076],{"class":373},"    rupt.",[356,1078,262],{"class":949},[356,1080,571],{"class":373},[356,1082,1083,1086,1088,1091],{"class":358,"line":591},[356,1084,1085],{"class":373},"        action ",[356,1087,378],{"class":955},[356,1089,1090],{"class":399}," \"access\"",[356,1092,588],{"class":373},[356,1094,1095,1098,1100],{"class":358,"line":606},[356,1096,1097],{"class":373},"        user ",[356,1099,378],{"class":955},[356,1101,1102],{"class":373}," user.id,\n",[356,1104,1105,1108,1110],{"class":358,"line":620},[356,1106,1107],{"class":373},"        email ",[356,1109,378],{"class":955},[356,1111,1112],{"class":373}," user.email,\n",[356,1114,1115,1118,1120],{"class":358,"line":633},[356,1116,1117],{"class":373},"        phone ",[356,1119,378],{"class":955},[356,1121,1122],{"class":373}," user.phone,\n",[356,1124,1126],{"class":358,"line":1125},14,[356,1127,1128],{"class":373},"    )\n",[356,1130,1132],{"class":358,"line":1131},15,[356,1133,445],{"class":373},[247,1135,1136,285,1139,289,1141,1143,1144,1146],{},[256,1137,1138],{},"detach",[256,1140,647],{},[256,1142,650],{}," are gone, and there is no longer a separate ",[256,1145,258],{}," call to repeat on resume.",[331,1148,658],{"id":1149},"step-3-show-challenges-through-the-container-1",[347,1151,1153],{"className":933,"code":1152,"language":935,"meta":352,"style":352},"setContent {\n    RuptContainer(rupt = rupt) {\n        \u002F\u002F your app content\n    }\n}\n",[256,1154,1155,1162,1175,1180,1185],{"__ignoreMap":352},[356,1156,1157,1160],{"class":358,"line":359},[356,1158,1159],{"class":949},"setContent",[356,1161,433],{"class":373},[356,1163,1164,1167,1170,1172],{"class":358,"line":366},[356,1165,1166],{"class":949},"    RuptContainer",[356,1168,1169],{"class":373},"(rupt ",[356,1171,378],{"class":955},[356,1173,1174],{"class":373}," rupt) {\n",[356,1176,1177],{"class":358,"line":420},[356,1178,1179],{"class":362},"        \u002F\u002F your app content\n",[356,1181,1182],{"class":358,"line":436},[356,1183,1184],{"class":373},"    }\n",[356,1186,1187],{"class":358,"line":442},[356,1188,445],{"class":373},[247,1190,1191,1192,1195,1196,1199],{},"View-system hosts skip the container, collect ",[256,1193,1194],{},"rupt.redirectURL"," in a lifecycle scope, and launch ",[256,1197,1198],{},"ChallengeActivity"," with the URL.",[331,1201,1203],{"id":1202},"android-events","Android events",[707,1205,1206,1217],{},[710,1207,1208],{},[713,1209,1210,1213,1215],{},[716,1211,1212],{},"v2 (2.1.0)",[716,1214,721],{},[716,1216,724],{},[726,1218,1219,1231,1243,1257,1269,1281,1291,1304,1314],{},[713,1220,1221,1225,1229],{},[731,1222,1223],{},[256,1224,427],{},[731,1226,1227],{},[256,1228,530],{},[731,1230,741],{},[713,1232,1233,1237,1241],{},[731,1234,1235],{},[256,1236,748],{},[731,1238,1239],{},[256,1240,753],{},[731,1242,741],{},[713,1244,1245,1250,1254],{},[731,1246,1247],{},[256,1248,1249],{},"onBackButtonCallback",[731,1251,1252],{},[256,1253,762],{},[731,1255,1256],{},"Renamed, and no longer passed the back state",[713,1258,1259,1263,1265],{},[731,1260,1261],{},[256,1262,776],{},[731,1264,779],{},[731,1266,782,1267,786],{},[256,1268,785],{},[713,1270,1271,1275,1277],{},[731,1272,1273],{},[256,1274,793],{},[731,1276,779],{},[731,1278,798,1279],{},[256,1280,310],{},[713,1282,1283,1287,1289],{},[731,1284,1285],{},[256,1286,807],{},[731,1288,779],{},[731,1290,812],{},[713,1292,1293,1298,1300],{},[731,1294,1295],{},[256,1296,1297],{},"shouldStartChallengeActivity",[731,1299,779],{},[731,1301,824,1302],{},[256,1303,306],{},[713,1305,1306,1308,1312],{},[731,1307,831],{},[731,1309,1310],{},[256,1311,836],{},[731,1313,839],{},[713,1315,1316,1318,1322],{},[731,1317,831],{},[731,1319,1320],{},[256,1321,848],{},[731,1323,851],{},[326,1325,1327],{"id":1326},"where-the-dropped-events-went","Where the dropped events went",[247,1329,1330],{},"The renamed callbacks are a straight swap. The dropped ones moved out of the client on purpose:",[1332,1333,1334,1346,1357,1369],"ul",{},[272,1335,1336,1339,1340,1342,1343,1345],{},[275,1337,1338],{},"Device limits"," (",[256,1341,776],{},") are now a policy on the access event. Set a ",[256,1344,785],{}," cap in the dashboard and the device-limit challenge does the capping. There is no client callback to wire.",[272,1347,1348,1339,1351,1353,1354,1356],{},[275,1349,1350],{},"The pre-challenge hook",[256,1352,793],{},") is gone because the SDK surfaces the challenge itself through ",[256,1355,310],{},". There is nothing to intercept.",[272,1358,1359,1339,1362,1364,1365,1368],{},[275,1360,1361],{},"The new-account hook",[256,1363,807],{},", and the ",[256,1366,1367],{},"new_account"," web view message) is gone because conversion is handled by the challenge's Success URL. Point it at your signup page.",[272,1370,1371,1339,1374,285,1376,1378,1379,1381,1382,1384,1385,1387],{},[275,1372,1373],{},"The presentation hooks",[256,1375,819],{},[256,1377,1297],{},") are replaced by the container. Adopt ",[256,1380,302],{}," or ",[256,1383,306],{},", or observe ",[256,1386,310],{}," and present it yourself.",[247,1389,1390,1392,1393,1395],{},[256,1391,836],{}," and ",[256,1394,848],{}," are optional. Use them only if you want to react when the user taps a button on the challenge.",[326,1397,1399],{"id":1398},"policies-and-challenge-urls","Policies and challenge URLs",[247,1401,1402,1403,1406,1407,1409],{},"The client swap above only wires up detection. What actually triggers a challenge is your policies, and those live in the dashboard, the same across every platform. Recreate the three default account-sharing checks (device limits, impossible travel, concurrency) and set the Success and Logout URLs by following Steps 3 and 4 of the ",[251,1404,1405],{"href":230},"web migration",". The Logout URL is where a device lands when the user logs it out from the challenge; ",[256,1408,530],{}," is the callback that fires when this session is logged out remotely.",[326,1411,1413],{"id":1412},"related","Related",[1332,1415,1416,1421],{},[272,1417,1418,1420],{},[251,1419,35],{"href":36},": the account-sharing fundamental in full.",[272,1422,1423,1425],{},[251,1424,229],{"href":230},": the web version of this migration.",[1427,1428,1429],"style",{},"html pre.shiki code .s42Qa, html code.shiki .s42Qa{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#88846F;--shiki-dark-font-style:inherit}html pre.shiki code .s2NTT, html code.shiki .s2NTT{--shiki-light:#F76D47;--shiki-default:#C678DD;--shiki-dark:#F92672}html pre.shiki code .sJCYa, html code.shiki .sJCYa{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#F8F8F2}html pre.shiki code .sKfv_, html code.shiki .sKfv_{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F92672}html pre.shiki code .sh6BQ, html code.shiki .sh6BQ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#66D9EF}html pre.shiki code .shEKG, html code.shiki .shEKG{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F8F8F2}html pre.shiki code .s9QZx, html code.shiki .s9QZx{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#E6DB74}html pre.shiki code .siibJ, html code.shiki .siibJ{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#E6DB74}html pre.shiki code .s4fYk, html code.shiki .s4fYk{--shiki-light:#FF5370;--shiki-default:#D19A66;--shiki-dark:#AE81FF}html pre.shiki code .seeE2, html code.shiki .seeE2{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#F8F8F2}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sAPXc, html code.shiki .sAPXc{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F92672;--shiki-dark-font-style:inherit}html pre.shiki code .sjp9t, html code.shiki .sjp9t{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#A6E22E}html pre.shiki code .sut_7, html code.shiki .sut_7{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F92672}html pre.shiki code .sDahn, html code.shiki .sDahn{--shiki-light:#39ADB5;--shiki-default:#E5C07B;--shiki-dark:#FD971F}html pre.shiki code .srTuz, html code.shiki .srTuz{--shiki-light:#39ADB5;--shiki-default:#C678DD;--shiki-dark:#F92672}",{"title":352,"searchDepth":366,"depth":366,"links":1431},[1432,1438,1444,1445,1446],{"id":328,"depth":366,"text":329,"children":1433},[1434,1435,1436,1437],{"id":333,"depth":420,"text":334},{"id":344,"depth":420,"text":345},{"id":657,"depth":420,"text":658},{"id":704,"depth":420,"text":705},{"id":854,"depth":366,"text":855,"children":1439},[1440,1441,1442,1443],{"id":858,"depth":420,"text":859},{"id":916,"depth":420,"text":345},{"id":1149,"depth":420,"text":658},{"id":1202,"depth":420,"text":1203},{"id":1326,"depth":366,"text":1327},{"id":1398,"depth":366,"text":1399},{"id":1412,"depth":366,"text":1413},"Move the v2 iOS and Android account-sharing integration onto v3. Which SDK events were renamed, which were dropped, and the step-by-step swap for each platform.","md",{},"---\ntitle: Account sharing on mobile\ndescription: Move the v2 iOS and Android account-sharing integration onto v3. Which SDK events were renamed, which were dropped, and the step-by-step swap for each platform.\n---\n\n# Account sharing on iOS and Android\n\nThe shift is the same as [on web](\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web): `attach` becomes `evaluate` with the `access` action. The bigger change on mobile is how challenges are shown and which callbacks exist. Three changes apply on both platforms:\n\n1. **One entry point.** Configuring the client, setting the user, and attaching collapse into a single `evaluate` call that takes `user`, `email`, and `phone` inline.\n2. **Challenges render through a container.** You add `RuptContainerView` (iOS) or `RuptContainer` (Android) to your UI and it observes `redirectURL`. The SDK no longer pushes its own view controller or activity, so the \"should present\" hooks are gone.\n3. **The callback set is smaller.** The device-limit and pre-challenge callbacks are dropped, and two challenge-button callbacks are added.\n\n::alert{type=\"warning\"}\nThis is a breaking upgrade. Every app needs code changes, and there is no compatibility shim. The steps below are the full swap.\n::\n\n## iOS (3.8.1 to 4.0.0)\n\n### Step 1: Replace the framework\n\nDownload the new `RuptClient.xcframework` and replace the old binary in your project.\n\n### Step 2: Create the client, then evaluate\n\n```swift\n\u002F\u002F v2\nlet rupt = Rupt(clientID: \"your_client_id\", useViewController: true)\nrupt.onLogoutCurrentDevice = {\n    \u002F\u002F Clear your session and sign the user out locally.\n}\nrupt.setUserID(user.id)\nrupt.setEmail(user.email)\nrupt.attach()\n```\n\n```swift\n\u002F\u002F v4\nlet rupt = Rupt(clientID: \"your_client_id\")\nrupt.onLogout = {\n    \u002F\u002F Fires when this session is logged out remotely. Clear your local session.\n}\n\n\u002F\u002F Same call site as attach: once per protected screen, for paying users.\ntry await rupt.evaluate(\n    action: \"access\",\n    user: user.id,\n    email: user.email,\n    phone: user.phone\n)\n```\n\n`setUserID`, `setEmail`, `setPhone`, `identify`, and `getHash` are gone. Pass the user inline to `evaluate` instead.\n\n### Step 3: Show challenges through the container\n\nWrap your root view so the challenge can overlay it:\n\n```swift\nRuptContainerView(rupt: rupt) {\n    \u002F\u002F your app content\n}\n```\n\nUIKit hosts skip the container, observe `$redirectURL`, and present the challenge web view themselves.\n\n### iOS events\n\n| v2 (3.8.1)                             | v4 (4.0.0)         | What changed                                          |\n| -------------------------------------- | ------------------ | ---------------------------------------------------- |\n| `onLogoutCurrentDevice`                | `onLogout`         | Renamed                                              |\n| `onChallengeCompleted`                 | `onComplete`       | Renamed                                              |\n| `onBackButtonPressed`                  | `onBackButtonPressed` | Unchanged                                         |\n| `onLimitExceeded`                      | Removed            | Cap devices with a `device_count` policy             |\n| `onChallenge`                          | Removed            | The SDK surfaces the challenge via `redirectURL`      |\n| `onCreateNewAccount`                   | Removed            | Conversion is handled by the challenge Success URL    |\n| `shouldPresentChallengeViewController` | Removed            | Use `RuptContainerView`                              |\n| Added                                  | `onPrimaryCta`     | Fires when the challenge primary button is tapped     |\n| Added                                  | `onSecondaryCta`   | Fires when the challenge secondary button is tapped   |\n\n## Android (2.1.0 to 4.0.0)\n\n### Step 1: Swap the dependency\n\nMove from JitPack to Maven Central:\n\n```groovy\n\u002F\u002F v2\nimplementation 'com.github.getrupt:kotlin:2.1.0'\n\n\u002F\u002F v4\nimplementation 'dev.rupt.android:rupt-android:4.0.0'\n```\n\nMake sure `mavenCentral()` is in your repositories.\n\n### Step 2: Create the client, then evaluate\n\nv2 was a `configure` plus `attach` on the `Rupt` singleton. v4 is an instance you create with your client ID.\n\n```kotlin\n\u002F\u002F v2\nRupt.configure(clientId = \"your_client_id\", account = user.id)\nRupt.onLogoutCurrentDevice = {\n    \u002F\u002F Clear your session and sign the user out locally.\n}\nRupt.attach(context = this)\n```\n\n```kotlin\n\u002F\u002F v4\nval rupt = Rupt(context = this, clientId = \"your_client_id\")\nrupt.onLogout = {\n    \u002F\u002F Fires when this session is logged out remotely. Clear your local session.\n}\n\n\u002F\u002F Same call site as attach: once per protected screen, for paying users.\nlifecycleScope.launch {\n    rupt.evaluate(\n        action = \"access\",\n        user = user.id,\n        email = user.email,\n        phone = user.phone,\n    )\n}\n```\n\n`detach`, `identify`, and `getHash` are gone, and there is no longer a separate `attach` call to repeat on resume.\n\n### Step 3: Show challenges through the container\n\n```kotlin\nsetContent {\n    RuptContainer(rupt = rupt) {\n        \u002F\u002F your app content\n    }\n}\n```\n\nView-system hosts skip the container, collect `rupt.redirectURL` in a lifecycle scope, and launch `ChallengeActivity` with the URL.\n\n### Android events\n\n| v2 (2.1.0)                  | v4 (4.0.0)            | What changed                                       |\n| --------------------------- | --------------------- | -------------------------------------------------- |\n| `onLogoutCurrentDevice`     | `onLogout`            | Renamed                                            |\n| `onChallengeCompleted`      | `onComplete`          | Renamed                                            |\n| `onBackButtonCallback`      | `onBackButtonPressed` | Renamed, and no longer passed the back state       |\n| `onLimitExceeded`           | Removed               | Cap devices with a `device_count` policy           |\n| `onChallenge`               | Removed               | The SDK surfaces the challenge via `redirectURL`   |\n| `onCreateNewAccount`        | Removed               | Conversion is handled by the challenge Success URL  |\n| `shouldStartChallengeActivity` | Removed            | Use `RuptContainer`                                |\n| Added                       | `onPrimaryCta`        | Fires when the challenge primary button is tapped   |\n| Added                       | `onSecondaryCta`      | Fires when the challenge secondary button is tapped |\n\n## Where the dropped events went\n\nThe renamed callbacks are a straight swap. The dropped ones moved out of the client on purpose:\n\n- **Device limits** (`onLimitExceeded`) are now a policy on the access event. Set a `device_count` cap in the dashboard and the device-limit challenge does the capping. There is no client callback to wire.\n- **The pre-challenge hook** (`onChallenge`) is gone because the SDK surfaces the challenge itself through `redirectURL`. There is nothing to intercept.\n- **The new-account hook** (`onCreateNewAccount`, and the `new_account` web view message) is gone because conversion is handled by the challenge's Success URL. Point it at your signup page.\n- **The presentation hooks** (`shouldPresentChallengeViewController`, `shouldStartChallengeActivity`) are replaced by the container. Adopt `RuptContainerView` or `RuptContainer`, or observe `redirectURL` and present it yourself.\n\n`onPrimaryCta` and `onSecondaryCta` are optional. Use them only if you want to react when the user taps a button on the challenge.\n\n## Policies and challenge URLs\n\nThe client swap above only wires up detection. What actually triggers a challenge is your policies, and those live in the dashboard, the same across every platform. Recreate the three default account-sharing checks (device limits, impossible travel, concurrency) and set the Success and Logout URLs by following Steps 3 and 4 of the [web migration](\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web). The Logout URL is where a device lands when the user logs it out from the challenge; `onLogout` is the callback that fires when this session is logged out remotely.\n\n## Related\n\n- [Access protection](\u002Fdocs\u002Fv3\u002Ffundamentals\u002Faccess-protection): the account-sharing fundamental in full.\n- [Account sharing on web](\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web): the web version of this migration.\n",{"title":233,"description":1447},"QRUoZByc2CbqHCm5D6OGLYDSdrhLWKySpRMn3L-RiVc",1782933210069]