How to add html to the "My user points" page (user points module)
You can find the menu path defined for " My User Points " page in userpoints.module file in hook_menu implementation..

  $items['myuserpoints'] = array(
    'title' =&gt; 'My !points',
    'title arguments' =&gt; userpoints_translation(),
    'page callback' =&gt; 'drupal_get_form',
    'page arguments' =&gt; array('userpoints_list_transactions'),
    'access callback' =&gt; 'userpoints_access_my_points',
    'file' =&gt; 'userpoints.pages.inc',
    'type' =&gt; MENU_NORMAL_ITEM,
    'menu_name' =&gt; 'user-menu',
  );


As you see above..

Page callback drupal_get_from with arguments "userpoints_list_transactions" is defined in "userpoints.pages.inc" file...

/**
 * Displays a detailed transaction report for an individual user.
 *
 * @param $account
 *   For which account to display. Defaults to the current user.
 */
function userpoints_list_transactions($form, &amp;$form_state, $account = NULL, $tid = NULL) {

  // If this is an AJAX request, update $_GET['q'] so that table sorting and
  // similar links are using the correct base path.
  if ($_GET['q'] == 'system/ajax') {
    $q = 'myuserpoints';
    if (!empty($account)) {
      $q = 'user/' . $account-&gt;uid . '/points';
    }
    $_GET['q'] = $q;
  }

  if (empty($account)) {
    global $user;
    $account = $user;
  }

  $settings = array(
    'show_user' =&gt; FALSE,
  );
  $header = userpoints_get_transaction_header($settings);

  $query = db_select('userpoints_txn', 'p')-&gt;extend('PagerDefault')-&gt;extend('TableSort')
    -&gt;fields('p')
    -&gt;condition('p.uid', $account-&gt;uid)
    -&gt;orderByHeader($header)
    // Enforce consistent sort order.
    -&gt;orderBy('p.txn_id', 'DESC')
    -&gt;limit(variable_get(USERPOINTS_REPORT_LIMIT, 10));

  if (module_exists('taxonomy')) {
    $query-&gt;leftJoin('taxonomy_term_data', 't', 'p.tid = t.tid');
  }

  $unapproved_query = db_select('userpoints_txn', 'p')
    -&gt;condition('uid', $account-&gt;uid)
    -&gt;condition('status', USERPOINTS_TXN_STATUS_PENDING);
  $unapproved_query-&gt;addExpression('SUM(points)');

  $values = userpoints_filter_parse_input($form_state, $tid);
  $active_category = userpoints_filter_query($query, $values);
  userpoints_filter_query($unapproved_query, $values);

  if (isset($active_category)) {
    drupal_set_title(t('!Points for @username (%category category)', userpoints_translation() + array('%category' =&gt; $active_category, '@username' =&gt; format_username($account))), PASS_THROUGH);
    $total_title = t('Total !points (%category category)', userpoints_translation() + array('%category' =&gt; $active_category));
  }
  else {
    drupal_set_title(t('!Points for @username', userpoints_translation() + array('@username' =&gt; format_username($account))));
    $total_title = t('Total !points', userpoints_translation());
  }

  $rows = array();
  foreach ($query-&gt;execute() as $transaction) {
    $rows[] = userpoints_get_transaction_row($transaction, $settings);
  }

  // Store context in the output array so that modules have access to it.
  $output = array(
    '#account' =&gt; $account,
    '#attached' =&gt; array(
      'css' =&gt; array(
        drupal_get_path('module', 'userpoints') . '/userpoints.css',
      ),
    ),
  );

  $output['form'] = userpoints_filter_form($account, $values);

  $output['list'] = array(
    '#type' =&gt; 'container',
    '#id' =&gt; 'userpoints_list_wrapper',
  );
  $output['list']['table'] = array(
    '#theme' =&gt; 'table',
    '#header' =&gt; $header,
    '#rows' =&gt; $rows,
    '#empty' =&gt; t('No !Points earned', userpoints_translation()),
    '#weight' =&gt; -5,
    '#attributes' =&gt; array('class' =&gt; array('userpoints-myuserpoints-list')),
  );
  $output['list']['pager'] = array(
    '#markup' =&gt; theme('pager'),
    '#weight' =&gt; 0,
  );

  // Fetch pending (not yet approved) points according to the category filter.
  $pending = (int)$unapproved_query
    -&gt;execute()
    -&gt;fetchField();

  // Display both pending and approved points in a simple table.
  $output['list']['summary_table'] = array(
    '#theme' =&gt; 'table',
    '#header' =&gt; array(
      array(
        'data' =&gt; $total_title,
        'colspan' =&gt; 2,
      ),
    ),
    '#rows' =&gt; array(
      array(
        'data' =&gt; array(t('Approved !points', userpoints_translation()), userpoints_get_current_points($account-&gt;uid, isset($values['tid']) ? $values['tid'] : 'all')),
        'class' =&gt; array('userpoints-myuserpoints-total-approved'),
      ),
      array(
        'data' =&gt; array(t('Pending !points', userpoints_translation()), $pending),
        'class' =&gt; array('userpoints-myuserpoints-total-pending'),
      ),
    ),
    '#weight' =&gt; 10,
    '#attributes' =&gt; array('class' =&gt; array('userpoints-myuserpoints-total')),
  );

  // For simplicity, the generated output is passed to a custom alter function.
  // This would also be possible through hook_page_alter(), but that hook is
  // hard to use.
  drupal_alter('userpoints_list_transactions', $output);

  return $output;
}


In the end you can see generated output is passed to a custom alter function

  drupal_alter('userpoints_list_transactions', $output);


By implementing hook_TYPE_alter()  in your custom module you can able to change the output..
i.e YOURMODULENAME_userpoints_list_transactions_alter function you need to implement..

/**
 * Implements hook_userpoints_list_transactions().
 */
function MODULENAME_userpoints_list_transactions_alter(&amp;$output) {
  // you can now change $output directly here
}


$output is a form variable.. You can add a new element to $output ..

/**
 * Implements hook_userpoints_list_transactions().
 */
function MODULENAME_userpoints_list_transactions_alter(&amp;$output) {
  // you can now change $output directly here
  $output['custom_text']['my_link'] = array(
    '#markup' =&gt; l("LINK", "Your Link"),
  );
  $output['custom_text']['my_text'] = array(
    '#markup' =&gt; 'Blah Blah',
  );
}