diff --git a/.changeset/mosaic-user-profile-export.md b/.changeset/mosaic-user-profile-export.md
new file mode 100644
index 00000000000..a845151cc84
--- /dev/null
+++ b/.changeset/mosaic-user-profile-export.md
@@ -0,0 +1,2 @@
+---
+---
diff --git a/integration/templates/next-app-router-mosaic/src/app/custom/page.tsx b/integration/templates/next-app-router-mosaic/src/app/custom/page.tsx
index 3656841dc26..8fc90b59a4a 100644
--- a/integration/templates/next-app-router-mosaic/src/app/custom/page.tsx
+++ b/integration/templates/next-app-router-mosaic/src/app/custom/page.tsx
@@ -4,7 +4,7 @@ import { MosaicProvider, UserButton } from '@clerk/mosaic';
export default function Page() {
return (
-
Terms body
}; +describe('UserButton with experimental.newProfiles', () => { + const newProfiles = { newProfiles: true }; + + async function renderWithNewProfiles(props: UserButtonProps = {}, seed: FakeFapiSeed = signedIn()) { + await page.viewport(1280, 800); + onTestFinished(() => page.viewport(414, 896)); + serveFapi(seed); + return renderWithClerk(tree(props), undefined, undefined, newProfiles); + } + + const profileTabs = () => screen.getAllByRole('tab').map(tab => tab.textContent); + + it('opens the combined UserProfile straight from Settings, without a menu, and closes', async () => { + const { clerk, navigate } = await renderWithNewProfiles(); + const openUserProfile = vi.spyOn(clerk, 'openUserProfile'); + const user = await open(); + + await user.click(screen.getByRole('button', { name: 'Settings' })); + + expect(screen.queryByRole('menu')).toBeNull(); + expect(await screen.findByRole('tab', { name: 'Account' })).toHaveAttribute('aria-selected', 'true'); + expect(profileTabs()).toEqual(['Account', 'Security', 'General', 'Members']); + expect(openUserProfile).not.toHaveBeenCalled(); + expect(navigate).not.toHaveBeenCalled(); + await waitFor(() => expect(popup()).toBeNull()); + }); + + it('opens the profile as a modal, so an OAuth connection returns to it', async () => { + await renderWithNewProfiles({}, withConnectedAccounts([])); + const request = holdRequests('post', '/v1/me/external_accounts'); + const user = await open(); + + await user.click(screen.getByRole('button', { name: 'Settings' })); + await user.click(await screen.findByRole('button', { name: 'Connect GitHub' })); + await waitFor(() => expect(request.requests).toHaveLength(1)); + + const body = new URLSearchParams(await request.requests[0]?.text()); + const encoded = new URL(body.get('redirect_url') || '').searchParams.get('__clerk_modal_state'); + expect(JSON.parse(window.atob(encoded || ''))).toMatchObject({ + componentName: 'UserProfile', + socialProvider: 'github', + }); + request.fail(); + }); + + it('opens the profile into the portal root the app provides', async () => { + await page.viewport(1280, 800); + onTestFinished(() => page.viewport(414, 896)); + const container = document.body.appendChild(document.createElement('div')); + onTestFinished(() => container.remove()); + serveFapi(signedIn()); + await renderWithClerk( +