Skip to main content
El widget Ayrshare Connect coloca nuestros botones de vinculación dentro de tu propio dashboard. Cargas un script, colocas un slot allí donde corresponda una red en tu layout, y nosotros renderizamos ahí un botón que ya muestra si la cuenta está conectada. Tu usuario hace clic y vincula la cuenta sin salir de tu página — como mucho una ventana emergente, la de la propia red. No escribes gestión de ventanas emergentes, ni callbacks de OAuth, ni refresco de sesión, ni lógica por red. Cuando una red cambia algo en su lado, la corrección llega dentro de nuestros frames en el momento en que la desplegamos; tú no redespliegas nada.

Qué superficie quieres

A customer dashboard with Ayrshare Connect tiles for Instagram, TikTok and LinkedIn embedded in a card

Frames incrustados: nuestras tarjetas renderizadas dentro de tu propio layout, un slot por red o un slot para varias.

A customer dashboard with its own Connect buttons and an Ayrshare popup showing the Facebook hand-off screen

Tu propio botón: tú renderizas el botón, y una breve ventana emergente nuestra se encarga de la red.

The hosted social linking page showing every available network

Página de vinculación alojada: una página alojada por nosotros, con tu logo y tus colores, que tu usuario abandona tu app para usar.

Las dos filas del widget son una sola integración, no dos. Un único init te da ambas: monta frames donde quieras nuestros botones y llama a popup() desde tu propio botón en el resto de sitios. Comparten una misma sesión y reportan en los mismos handlers.El modo directo (Direct Mode) es la misma ventana emergente sin nuestro script — para una página con una Content-Security-Policy estricta, una página renderizada en servidor o una app nativa. Ahí abres y supervisas la ventana emergente tú mismo.

Añade el script

Fija una versión y su hash, o sigue un canal sin él. Nunca ambas cosas — un atributo integrity en una URL que se mueve deja de funcionar en nuestra siguiente versión, porque el archivo que nombra ha cambiado legítimamente.
Pinned version
Tracking v1
v1 es el canal recomendable. Recoge correcciones pero nunca cruza un cambio incompatible. latest cruza versiones mayores por definición, así que en algún momento entregará a tu página una versión cuyo comportamiento no has revisado. El hash de cada versión se publica en manifest.json, que también indica qué sirve actualmente cada canal:
manifest.json
Cada bundle además empieza con un comentario que indica su propia versión, que es la forma más rápida de decirnos qué está ejecutando realmente una página:

Content-Security-Policy

Si tu página envía una Content-Security-Policy, necesita dos entradas, ambas con el host desde el que cargas el script:
Esa es toda la lista. No necesitas ninguna entrada connect-src para nosotros — nuestros frames llegan a nuestra API desde dentro de sí mismos, no desde tu página — y ninguna entrada para ventanas emergentes, que son ventanas de nivel superior que tu política no gobierna. Ambas entradas están medidas: quitar script-src bloquea el script, y quitar frame-src bloquea el frame.

Inicia una instancia

session es la única opción obligatoria. Se llama una vez por instancia, no una vez por mount, y debe devolver la respuesta de tu backend a Crear una Link Session con mode: "connect" — { sessionId, token, expiresAt } — exactamente como llegó.
Your page
Your backend
Una sesión del widget no nombra ningún network — autoriza todas las redes que tu cuenta permite, y cuáles aparecen se decide por mount, en tu página. Sí lleva un origin, que es lo único que hace que los frames se rendericen: un frame comprueba la página que lo incrusta contra ese valor y se niega a renderizarse en cualquier otro sitio.
Crea la sesión en tu servidor. La llamada necesita tu API Key, y el token que devuelve inicia la sesión de tu usuario en su User Profile — trátalo como una contraseña.
Volvemos a llamar a session antes de que el token caduque, así que el widget sigue funcionando en una página que se deja abierta todo el día. Una llamada que rechaza, o que no devuelve ningún token, se reintenta dos veces más — a los 0,5 s y luego a 1 s — antes de rendirnos y emitir error. Así que un refresco cuesta como mucho tres llamadas a tu endpoint.

Monta un slot

Un mount por slot. Pide una red, varias o todo lo que la sesión permita — la granularidad es tuya, así que un slot puede ser una única fila de una tabla existente o un panel que lo contenga todo.
mount acepta un selector CSS o un elemento, y devuelve { unmount, element }. Lanza una excepción si el destino no coincide con nada — que casi siempre es un slot que todavía no existe, así que monta después de que tu marcado esté en el documento. Cada mount es un iframe. Nos informa de su propia altura y lo redimensionamos para que coincida, de modo que tu layout se reajusta cuando nuestro contenido cambia; pasado maxHeight el frame se desplaza internamente en lugar de salirse de tu página. El slot más estrecho que admitimos es de 300px. Las claves de red son las propias de Ayrshare, y las grafías alias también funcionan: instagram e instagramapi significan ambas instagramApi, y x significa twitter. Una clave que no es una red no renderiza ninguna tarjeta.

Tu propio botón

Un cliente que prefiera usar su propio botón en lugar de uno de nuestros frames llama a popup en su lugar. Ejecuta el mismo flujo, sobre la misma sesión, y reporta en los mismos handlers.
Llámalo directamente dentro del manejador de clic, sin nada awaited antes. Un navegador solo permite una ventana emergente mientras todavía está procesando el clic de tu usuario, y ese permiso no sobrevive a un await. De todos modos no hay nada que esperar — la sesión se creó en init.
popup devuelve { close(), network }, y siempre devuelve un handle — incluso tras una ventana emergente bloqueada, donde close() no hace nada — de modo que tu código nunca tiene que comprobar null antes de llamar a close(). Todas las redes funcionan aquí, incluidas las que un frame termina dentro de su propio panel: Facebook muestra su pantalla explicativa de traspaso en la ventana emergente, Bluesky y X muestran su formulario de credenciales, y LinkedIn, Pinterest, YouTube y Google Business salen a la red y vuelven. Lanza una excepción síncrona en los tres casos que son errores de programación — ningún network, una instancia destruida, o una sesión que aún no se ha resuelto. Una ventana emergente bloqueada no es uno de ellos: eso emite error con reason: "popupBlocked", porque tu usuario no hizo nada mal. Como mucho hay una ventana emergente abierta a la vez. Una segunda llamada cierra la primera y reporta cancelled con reason: "superseded" sobre ella. Una ventana emergente abierta por uno de nuestros frames es otra cosa y nunca se toca, así que tu botón no puede cancelar un flujo en curso dentro de un slot montado.
Si la sesión puede vincular una red es una respuesta del servidor, no del script. Una sesión limitada a Bluesky a la que se le pide LinkedIn recibe un rechazo renderizado en la ventana emergente y reportado como error. El script solo comprueba que se haya nombrado alguna red.

React

El script no depende de ningún framework, así que React no necesita nada especial de nosotros — pero hay cuatro cosas de su ciclo de vida que conviene hacer bien a la primera. Carga el script una vez, fuera de tu árbol de componentes. En Next.js eso es next/script en tu layout raíz; en Vite o Create React App es una etiqueta en index.html. Cargarlo por componente lo vuelve a ejecutar en cada mount.
ConnectAccounts.jsx
Nunca reutilices una instancia después de destroy(). Una instancia destruida se queda destruida — popup() lanza una excepción sobre ella, y mount() no la revivirá. Crea una nueva instancia en la siguiente ejecución del efecto, que es lo que hace el código de arriba.
Dos consecuencias de ese patrón, y ninguna es un bug:
  • En desarrollo verás el callback de sesión dispararse dos veces. El Strict Mode de React ejecuta los efectos mount → unmount → mount, así que la instancia se crea, se destruye y se vuelve a crear. La limpieza de arriba hace que eso sea seguro; cuesta una llamada extra a tu backend en desarrollo y ninguna en producción.
  • Mantén estables las dependencias del efecto. Un array literal pasado directamente a mount desde el render de un padre es un valor nuevo cada vez, así que un efecto que dependa de él desmonta el widget y lo reconstruye en cada render. Memoízalo, o mantenlo constante como arriba.

Eventos

Suscríbete con on, que devuelve una función para cancelar la suscripción. Los handlers reciben el payload del evento y el mount del que procede; off(name, handler) hace el mismo trabajo cuando prefieres nombrar el handler.
Diez eventos. Todos llevan un network excepto ready, y excepto el único tipo de error que no trata de ninguna red — consulta error tiene dos orígenes más abajo. Cuatro de ellos son finales — success, unlinked, error y cancelled — y llega exactamente uno por intento. closed es un aviso de ciclo de vida que sigue a un final, no un final en sí. click se dispara antes de que empiece cualquier trabajo de vinculación, así que reporta un clic que una ventana emergente bloqueada o una sesión muerta rechazará después. Es el evento que usar para tus propias analíticas; started es el que significa que un intento está realmente en marcha.

Razones

error tiene dos orígenes

Solo uno de ellos es un fallo de vinculación, y llevan campos distintos.
  • Un error de vinculación lleva network, code y el mount del que procede.
  • Un error de sesión — no pudimos crear o refrescar tu sesión — lleva solo message, porque no se estaba vinculando nada en ese momento.
Desestructura a la defensiva: code y network son undefined en el segundo tipo.

state te ahorra el polling

state es el canal de datos, más que un informe sobre un intento. Cada frame emite uno por red al montarse, con el estado actual de esa red y la marca de tiempo since desde la que lo mantiene, y otro cada vez que un estado cambia — incluidos los cambios que se originan en nuestro lado, como un token que muere y pasa a requerir revinculación. Así que puedes alimentar toda tu UI desde el widget sin hacer polling de nada. Los valores son el mismo enum que devuelve GET /profiles con include=state: linked, unlinked, identityVerificationRequired, restricted, rateLimited, suspended.

Desvincular

Nuestras tarjetas desvinculan además de vincular. Tu usuario hace clic en una red conectada, confirma, y la cuenta se elimina:
  1. click se dispara con action: "unlink".
  2. unlinked se dispara una vez que la eliminación está guardada.
Una desvinculación que falla reporta error, y una de la que tu usuario se echa atrás en el paso de confirmación reporta cancelled. No hay un evento separado de desvinculación fallida.

Apariencia

La hoja de estilos de un cliente no puede llegar al interior de un frame cross-origin, así que los estilos viajan como datos que aplicamos dentro de él. Pasa appearance a init como propiedades personalizadas de CSS; cada una que no recibamos conserva nuestro valor por defecto.
Define los colores en pares. Un token de fondo sin su token de primer plano al lado es la única manera de que esto produzca algo ilegible: pon --ayr-connect-surface-bg en un valor oscuro por sí solo y nuestro --ayr-connect-surface-fg por defecto sigue siendo azul marino oscuro. Nada puede inferir la otra mitad por ti.
Sin ningún appearance, cada token conserva su valor por defecto y un frame tiene este aspecto:
Three Ayrshare Connect tiles with the default appearance

Tokens por defecto: superficies blancas, texto azul marino oscuro, acento índigo, radio de 8px.

Pasa un puñado de tokens y el mismo frame adopta tu paleta. Este ejemplo vuelve las superficies azul pálido, oscurece el texto y el acento para que combinen, y redondea las esquinas un poco más:
Three Ayrshare Connect tiles restyled with pale blue surfaces and a deeper blue accent

Las mismas tres tarjetas después de aplicar los tokens de arriba.

Hay una sola paleta y ningún preajuste claro/oscuro. Nada depende de prefers-color-scheme, a propósito — el tema de tu página puede no coincidir con el sistema operativo de tu usuario, y una media query invalidaría silenciosamente los colores que elegiste. Un dashboard oscuro se tematiza suministrando valores oscuros. Esta lista de tokens es un contrato soportado que mantenemos entre versiones.

Los tokens

Un valor que no sea CSS válido para su token se ignora, con una advertencia en tu consola, en lugar de aplicarse. Eso importa más de lo que parece: un 8 sin unidad para --ayr-connect-spacing es una cadena perfectamente inocente que invalidaría cada cálculo que la lea y colapsaría el layout, sin ningún error en ninguna parte. Dales unidad a las longitudes.

Tu propio nombre en la pantalla de traspaso

Antes de entregar tu usuario a una red, mostramos una breve pantalla que indica a través de quién se está conectando. Dos ganchos te permiten hacerla tuya, y ambos son estables entre versiones. --ayr-connect-partner-name establece la etiqueta. Es el único token cuyo valor es texto, así que tiene que ir entrecomillado como una cadena CSS — un valor sin comillas es inválido y no renderiza nada en absoluto:
El logo no es un token. Servimos la marca como un elemento posicionado y dimensionado, y tú lo rellenas con una background-image mediante css, como arriba — un token que pudiera cargar una imagen desde dentro de nuestro documento no es algo que aceptemos, así que la petición procede de una regla que escribiste tú y no de un valor que nos pasaste.
[data-ayr-connect-partner-mark] y [data-ayr-connect-partner-name] son la excepción a la advertencia sobre CSS personalizado de abajo: estos dos selectores forman parte del contrato y los mantenemos entre versiones.

CSS personalizado

css acepta una cadena que se aplica dentro de cada frame, para los casos que los tokens no cubren.
El CSS personalizado no está soportado entre versiones. Sus selectores apuntan a nuestro marcado interno, que cambia entre releases — una regla que funciona hoy puede dejar de coincidir silenciosamente tras cualquier actualización. El contrato de tokens de arriba es la parte que mantenemos. Fija una versión si dependes de CSS personalizado.
Las ventanas emergentes heredan el appearance y el css de la instancia exactamente igual que los frames, así que tu usuario no ve aparecer nuestros valores neutros por defecto a mitad de un flujo.

Cosas que conviene saber antes de lanzar

A una ventana emergente que abriste con popup() no se le puede decir por qué se rechazó un token — para hacerlo tendría que confiar en un origen que aún no ha validado, cosa que nuestro modelo de seguridad no permite. Así que una ventana emergente con un token muerto se cierra y aflora como cancelled con reason: "popupClosed" en lugar de error.En la práctica esto es raro: una ventana emergente abierta antes de un refresco silencioso sigue funcionando, porque validó su token al abrirse. Si ves resultados popupClosed sin explicación, comprueba que tu endpoint de session esté devolviendo una sesión nueva.
Catorce mounts comparten un token y cuestan una llamada a tu backend, no catorce. Si quieres slots con distinto alcance — un allowedSocial distinto en algunos — ejecuta un segundo init con su propia sesión en lugar de esperar que un mount la acote.
Cada sesión lleva el origin en el que corre tu página, y un frame compara la página que lo incrusta contra ese valor antes de renderizar nada. Un frame incrustado en otro sitio se queda en blanco y no envía eventos. No hay ninguna allowlist que registrar ni nada que configurar — envía el origin correcto al crear la sesión.
Los frames informan de su altura al script, y el script los redimensiona. Tu layout simplemente se reajusta. No hay ningún evento resize al que suscribirse, ni nada que medir en tu lado.

Requisitos

  • El Max Pack. Una sesión del widget es una sesión en modo connect, y crear una sin el Max Pack devuelve code: 504. Contacta con soporte si necesitas habilitar el modo connect en una cuenta sin él.
  • Un origin en cada sesión — el origen exacto en el que corre tu página. Omitirlo devuelve code: 505; un valor que no sea un origen https, un esquema personalizado o http://localhost devuelve code: 506.
  • Ningún network en la sesión. Ese parámetro es lo que convierte una sesión en modo directo, y la URL de una sesión en modo directo no es lo que el script espera.
Todos los códigos de arriba están en la referencia de Errores de link session, con el mensaje exacto que devuelve la API y qué hacer al respecto.