> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Cómo alojar bots de X (Twitter)

> Aprende a crear y alojar un bot de X (Twitter) en Square Cloud. Tutorial completo con configuración, despliegue y ejemplos prácticos en Node.js y Python.

export const RecommendedPlan = ({lang, plan, tier, cpu, appType}) => {
  const url = `https://squarecloud.app/${lang}/pay?plan=${plan.toLowerCase()}&tier=${tier}`;
  if (lang == 'en') {
    return <Note>
        <b>Wondering how much RAM and CPU your plan needs to host {appType}?</b><br />
        Don't worry, we're here to help.
        Our <a href={url}>{plan}</a> plan offers <b>{tier}GB</b> of RAM and <b>{cpu}vCPU</b>, which should be sufficient for most {appType}. 
        However, if you are working on a larger project and seeking extra stability, we recommend considering our <b>Pro</b> plan. With additional resources, you can maintain stability even during demand spikes. 
        To purchase, simply click <a href="https://squarecloud.app/en/pay?plan=pro">here</a>.
      </Note>;
  } else {
    return <Note>
          <b>Está se perguntando quanta RAM e CPU seu plano precisa para hospedar {appType}?</b><br />
          Não se preocupe, estamos aqui para ajudar.
          Nosso plano <a href={url}>{plan}</a> oferece <b>{tier}GB</b> de RAM e <b>{cpu}vCPU</b>, o que deve ser suficiente para a maioria dos {appType}.
          No entanto, se você estiver trabalhando em um projeto maior e precisar de mais estabilidade, recomendamos considerar nosso plano <b>Pro</b>.
          Com recursos adicionais, você pode manter a estabilidade mesmo durante picos de demanda.
          Para comprar, basta clicar <a href={`https://squarecloud.app/${lang}/pay?plan=pro`}>aqui</a>.
        </Note>;
  }
};

export const appType_0 = "a X (Twitter) bot"

## Introducción

Para desarrollar y alojar {appType_0} en Square Cloud, es esencial seguir una secuencia estructurada de configuraciones y requisitos previos. Esta guía técnica cubrirá todo el proceso, desde la configuración inicial hasta el despliegue en producción.

### Requisitos previos

* **Cuenta de Square Cloud**: Regístrate a través de la [página de registro](https://squarecloud.app/es/signup) usando tu correo electrónico.
* **Plan de pago activo**: Garantiza recursos dedicados y un rendimiento optimizado para tu aplicación. Consulta nuestros [planes disponibles](https://squarecloud.app/es/pricing) y elige el más adecuado para tus necesidades.

<RecommendedPlan appType="X (Twitter)" plan="Hobby" tier="2" cpu="2" lang="en" />

### Creando el proyecto

Se requiere una cuenta activa de X (Twitter) para la autenticación y el funcionamiento del bot. Si no tienes una cuenta, regístrate en el [sitio web oficial de X](https://x.com/).\
También se requiere una cuenta de X Developer para acceder a las APIs. Solicita acceso a través del [Portal de Desarrolladores de X](https://developer.x.com/en).

### Aplicación del bot en X

<Steps>
  <Step title="Accediendo al Portal de Desarrolladores">
    1. Ve al [Portal de Desarrolladores de X](https://developer.x.com/en/portal/dashboard).
    2. Inicia sesión con tu cuenta de X (Twitter).
    3. Si es tu primera vez, completa el proceso de solicitud de acceso de desarrollador.
  </Step>

  <Step title="Creación del proyecto">
    1. En el panel, haz clic en "Create Project".
    2. Elige un nombre para tu proyecto (por ejemplo, "Square Cloud Bot").
    3. Selecciona el caso de uso más apropiado (por ejemplo, "Making a bot").
    4. Proporciona una descripción detallada de tu bot.
    5. Confirma la creación del proyecto.
  </Step>

  <Step title="Configuración de la aplicación">
    1. Dentro del proyecto creado, haz clic en "Create App".
    2. Define un nombre único para tu aplicación.
    3. Confirma la creación de la aplicación.
    4. Anota el **App ID** generado para futuras referencias.
  </Step>

  <Step title="Generación de las claves de API">
    1. Navega a la sección "Keys and tokens" de tu aplicación.
    2. En la sección "Consumer Keys", haz clic en "Regenerate" para generar:
       * **API Key** (Consumer Key)
       * **API Secret Key** (Consumer Secret)
    3. **Importante**: Copia y guarda estas claves de inmediato, ya que no podrás volver a verlas.
  </Step>

  <Step title="Configuración de permisos">
    1. Ve a la sección "App permissions".
    2. Haz clic en "Edit" para modificar los permisos.
    3. Selecciona "Read and write" para permitir que tu bot publique tweets.
    4. Si es necesario, selecciona "Read and write and Direct message" para la funcionalidad de DM.
    5. Guarda los cambios.
  </Step>

  <Step title="Generación de los tokens de acceso">
    1. Regresa a la sección "Keys and tokens".
    2. En la sección "Access Token and Secret", haz clic en "Generate".
    3. Confirma la generación del token.
    4. Copia y guarda:
       * **Access Token**
       * **Access Token Secret**
    5. **Advertencia**: Estos tokens no podrán volver a verse después de cerrar la página.
  </Step>

  <Step title="Verificación de credenciales">
    1. Confirma que tienes las 4 credenciales requeridas:
       * API Key (Consumer Key)
       * API Secret Key (Consumer Secret)
       * Access Token
       * Access Token Secret
    2. Almacena estas credenciales en un lugar seguro
    3. **Importante**: Nunca compartas ni expongas estas credenciales públicamente
  </Step>
</Steps>

## Desarrollando el proyecto

1. **Verificación de Node.js**: Verifica que Node.js esté instalado en tu sistema. Si no, descárgalo desde el [sitio web oficial de Node.js](https://nodejs.org/).

2. **Inicialización del proyecto**: Crea un nuevo proyecto de Node.js ejecutando:

```bash Terminal theme={null}
npm init -y
```

3. **Instalar dependencias**: Instala las bibliotecas necesarias para el bot:

```bash Terminal theme={null}
npm install twitter-api-v2
```

4. **Configuración de variables de entorno**: Crea un archivo `.env` para almacenar tus credenciales de forma segura:

```env .env theme={null}
API_KEY=your_api_key_here
API_SECRET_KEY=your_api_secret_key_here
ACCESS_TOKEN=your_access_token_here
ACCESS_TOKEN_SECRET=your_access_token_secret_here
```

5. **Crear el archivo principal**: Desarrolla el archivo `index.js` con la estructura base del bot:

```javascript index.js theme={null}
// Import necessary modules
const { TwitterApi } = require('twitter-api-v2');

// Configure Twitter client with authentication
const client = new TwitterApi({
  appKey: process.env.API_KEY,
  appSecret: process.env.API_SECRET_KEY,
  accessToken: process.env.ACCESS_TOKEN,
  accessSecret: process.env.ACCESS_TOKEN_SECRET,
});

// Client with read and write permissions
const rwClient = client.readWrite;

// Stores the authenticated bot user id (set in verifyBot)
let botUserId = null;

// Function to check if the bot is working
async function verifyBot() {
  try {
    // Get authenticated user information (X API v2)
    const me = await rwClient.v2.me();
    botUserId = me.data.id;
    console.log(`Bot successfully initialized! User: @${me.data.username}`);
    return true;
  } catch (error) {
    console.error('Error verifying bot:', error);
    return false;
  }
}

// Function to post a tweet
async function postTweet(text) {
  try {
    const tweet = await rwClient.v2.tweet(text);
    console.log(`Tweet posted successfully! ID: ${tweet.data.id}`);
    return tweet;
  } catch (error) {
    console.error('Error posting tweet:', error);
    throw error;
  }
}

// Function to respond to mentions
async function respondToMentions() {
  if (!botUserId) return;
  try {
    // Fetch recent mentions (X API v2)
    const mentions = await rwClient.v2.userMentionTimeline(botUserId, {
      max_results: 10,
    });

    for (const tweet of mentions.data?.data ?? []) {
      // Check if it's a new mention (implement control logic)
      if (tweet.text.includes('!ping')) {
        // Reply to the mention
        await rwClient.v2.reply(
          'Pong! 🤖 X Bot working correctly!',
          tweet.id
        );
        console.log(`Replied to mention (tweet ID: ${tweet.id})`);
      }
    }
  } catch (error) {
    console.error('Error processing mentions:', error);
  }
}

// Function to search and interact with specific tweets
async function searchAndInteract(query) {
  if (!botUserId) return;
  try {
    // Search recent tweets (X API v2)
    const tweets = await rwClient.v2.search(query, {
      max_results: 10,
    });

    for (const tweet of tweets.data?.data ?? []) {
      // Like the tweet
      await rwClient.v2.like(botUserId, tweet.id);
      console.log(`Liked tweet ID: ${tweet.id}`);

      // Wait a bit between actions to avoid rate limiting
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  } catch (error) {
    console.error('Error searching and interacting:', error);
  }
}

// Main bot function
async function runBot() {
  console.log('Starting X bot...');
  
  // Check if the bot is configured correctly
  const botOk = await verifyBot();
  if (!botOk) {
    console.error('Bot initialization failed');
    return;
  }
  
  // Example: Post an initialization tweet
  try {
    await postTweet('🤖 X Bot initialized and running on Square Cloud!');
  } catch (error) {
    console.log('Initialization tweet failed, but bot continues running');
  }
  
  // Main bot loop
  setInterval(async () => {
    try {
      // Check and respond to mentions every 5 minutes
      await respondToMentions();
      
      // Example: Search and interact with tweets about a specific topic
      // await searchAndInteract('#SquareCloud');
      
    } catch (error) {
      console.error('Error in main loop:', error);
    }
  }, 5 * 60 * 1000); // 5 minutes
  
  console.log('Bot running. Press Ctrl+C to stop.');
}

// Signal handling for graceful shutdown
process.on('SIGINT', () => {
  console.log('\nShutting down X bot...');
  process.exit(0);
});

process.on('SIGTERM', () => {
  console.log('\nShutting down X bot...');
  process.exit(0);
});

// Initialize the bot
runBot();
```

## Desplegando

Tras preparar los archivos de tu proyecto, ya puedes subirlos a Square Cloud y alojar tu proyecto.
Para ello, crea un archivo ZIP que contenga todos los archivos de tu proyecto.

<AccordionGroup>
  <Accordion title="Variables de entorno" icon="key">
    <Note>**Seguridad**: Nunca incluyas tus credenciales de la API directamente en el código. Usa siempre variables de entorno en Square Cloud.</Note>

    En Square Cloud, configura las siguientes variables de entorno a través del panel de control:

    * `API_KEY`: Tu clave de API de X
    * `API_SECRET_KEY`: Tu clave secreta de API de X
    * `ACCESS_TOKEN`: Tu token de acceso
    * `ACCESS_TOKEN_SECRET`: Tu secreto del token de acceso
  </Accordion>
</AccordionGroup>

### A través del panel

<Steps>
  <Step title="Accede a la página de subida">
    Accede a la [página de subida](https://squarecloud.app/es/dashboard/new) y sube el archivo zip de tu proyecto.
  </Step>

  <Step title="Configura tu entorno">
    Después de subir tu zip, deberás configurar el nombre, el archivo principal o el entorno de ejecución y otros ajustes de tu proyecto.\
    Si estás subiendo un proyecto web, asegúrate de seleccionar "Publicación Web" y de definir un subdominio para tu proyecto.
  </Step>

  <Step title="Despliega tu proyecto">
    Por último, haz clic en el botón "Deploy" para alojar tu proyecto en Square Cloud.\
    Tras el despliegue, puedes monitorear el estado y los logs de tu proyecto desde el panel.

    <Frame>
      <img src="https://cdn.squarecloud.app/docs/articles/dashboard/uploading.gif" alt="Subiendo aplicación a Square Cloud" style={{ borderRadius: "0.2rem" }} />
    </Frame>
  </Step>
</Steps>

### A través de la CLI

Para usar este método, necesitas crear un archivo de configuración llamado `squarecloud.app` en el directorio raíz de tu proyecto. Este archivo contendrá la configuración necesaria para tu proyecto.

<Card title="Aprende más sobre: cómo crear el archivo de configuración para Square Cloud." icon="link" href="/es/getting-started/config-file">
  El archivo squarecloud.app es un archivo de configuración que se usará para configurar tu aplicación; se utilizará para definir tu entorno.
</Card>

<Steps>
  <Step title="Instala la CLI">
    Primero, necesitas tener la CLI instalada en tu entorno. Si aún no la tienes, ejecuta el siguiente comando en tu terminal:

    ```
    npm install -g @squarecloud/cli
    ```

    Si ya la tienes, te recomendamos actualizarla. Para ello, ejecuta el siguiente comando en tu terminal:

    <Tabs>
      <Tab title="Windows">
        ```bash theme={null}
        squarecloud update
        ```
      </Tab>

      <Tab title="Linux, macOS y WSL">
        ```bash theme={null}
        curl -fsSL https://cli.squarecloud.app/install | bash
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Autentícate">
    Ahora, para autenticarte y usar otros comandos de la CLI, encontrarás tu clave de autorización [aquí](https://squarecloud.app/es/account/security) haciendo clic en "Request API Key". Después de obtener tu clave de autorización, ejecuta el siguiente comando:

    ```bash theme={null}
    squarecloud auth login
    ```
  </Step>

  <Step title="Sube tu proyecto">
    Por último, para desplegar tu aplicación en Square Cloud usando la CLI, necesitas ejecutar el siguiente comando:

    ```bash theme={null}
    squarecloud upload 
    ```

    O si creaste el zip manualmente, puedes usar:

    ```bash theme={null}
    squarecloud upload --file <path/to/zip> 
    ```
  </Step>
</Steps>

## Recursos adicionales

Para profundizar tus conocimientos sobre el desarrollo de bots de X usando twitter-api-v2, consulta la [documentación oficial de la biblioteca twitter-api-v2](https://github.com/PLhery/node-twitter-api-v2). La documentación proporciona guías detalladas, tutoriales avanzados y referencias completas de la API para maximizar tu implementación.

Consulta también:

* [Documentación oficial de la API de X](https://docs.x.com/overview)
* [Políticas de uso de la API de X](https://developer.x.com/en/developer-terms/policy)
* [Guía de buenas prácticas para bots](https://docs.x.com/x-api/getting-started/about-x-api)

### Monitoreo de hashtags

```javascript theme={null}
// Function to monitor specific hashtags
async function monitorHashtags(hashtags) {
  for (const hashtag of hashtags) {
    try {
      const tweets = await rwClient.v2.search(`#${hashtag}`, {
        max_results: 10,
      });

      // Process found tweets
      for (const tweet of tweets.data?.data ?? []) {
        console.log(`Tweet found with #${hashtag}: ${tweet.text}`);
        // Implement interaction logic
      }
    } catch (error) {
      console.error(`Error monitoring #${hashtag}:`, error);
    }
  }
}
```

### Publicaciones programadas

```javascript theme={null}
// Function to schedule posts
function schedulePost(text, delay) {
  setTimeout(async () => {
    try {
      await postTweet(text);
      console.log('Scheduled post published successfully!');
    } catch (error) {
      console.error('Error publishing scheduled post:', error);
    }
  }, delay);
}

// Example: Schedule a post for 1 hour
schedulePost('🤖 Scheduled post by the bot!', 60 * 60 * 1000);
```

### Rate Limiting

X (Twitter) tiene límites de tasa estrictos. Implementa controles para evitar exceder estos límites:

```javascript theme={null}
// Rate limiting control
const rateLimiter = {
  lastRequest: 0,
  minInterval: 1000, // 1 second between requests
  
  async wait() {
    const now = Date.now();
    const timeSinceLastRequest = now - this.lastRequest;
    
    if (timeSinceLastRequest < this.minInterval) {
      const waitTime = this.minInterval - timeSinceLastRequest;
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
    
    this.lastRequest = Date.now();
  }
};
```

### Manejo de errores

```javascript theme={null}
// Helper function to retry an operation on failure
async function retryOperation(operation, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation();
    } catch (error) {
      console.error(`Attempt ${i + 1} failed:`, error.message);
      
      if (i === maxRetries - 1) {
        throw error;
      }
      
      // Wait before retrying
      await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
    }
  }
}
```

## Contáctanos

Si continúas enfrentando **dificultades técnicas**, nuestro **equipo de soporte especializado** está disponible para ayudarte. [**Contáctanos**](https://squarecloud.app/es/support) y estaremos encantados de ayudarte a resolver cualquier problema.
