Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track methods not generated (Browser Javascript) #98

Open
Zaimwa9 opened this issue May 4, 2022 · 4 comments
Open

Track methods not generated (Browser Javascript) #98

Zaimwa9 opened this issue May 4, 2022 · 4 comments

Comments

@Zaimwa9
Copy link

Zaimwa9 commented May 4, 2022

Hi,

I don't know where to ask my question. I've set up the new Data (beta) -To be honest I was happy with itly, anyways-. I have created events, pushed the latest version.

Even when I ampli pull, no methods are generated. I must use .track({event_type: "xx"}) which is completely opposed to why I wanted to implement data beta

Here is my generated ampli/index.js (without sensitive data) and below a screenshot of the tracking plan.

Please help 😄 It would be awesome!

image

import amplitude from 'amplitude-js';

/**
 * @typedef BaseEvent
 * @type {object}
 * @property {string} event_type
 * @property {Object.<string, *>} [event_properties]
 */

/**
 * @typedef Plan
 * @type {object}
 * @property {string} [branch]
 * @property {string} [source]
 * @property {string} [version]
 * @property {string} [versionId]
 */

/**
 * Data to be processed by middleware
 * @typedef MiddlewarePayload
 * @type {object}
 * @property {BaseEvent} event
 * @property {MiddlewareExtra} [extra]
 */

/**
 * Function called at the end of each Middleware to run the next middleware in the chain
 * @typedef MiddlewareNext
 * @type {function}
 * @param {MiddlewarePayload} payload
 *
 * @return
 */

/**
 * A function to run on the Event stream (each logEvent call)
 * @typedef Middleware
 * @type {function}
 * @param {MiddlewarePayload} payload The event and extra data being sent
 * @param {MiddlewareNext} next Function to run the next middleware in the chain, not calling next will end the middleware chain
 * @return
 */

/**
 * @typedef LoadClientOptions
 * @type {object}
 * @property {string} [apiKey]
 * @property {Object} [options]
 * @property {AmplitudeClient} [instance]
 */

/**
 * @typedef LoadOptions
 * @type {object}
 * @property {'development'|'production'} [environment]
 * @property {boolean} [disabled]
 * @property {LoadClientOptions} [client]
 */

/**
 * @typedef {Object} EventOptions
 * @type {object}
 */

/**
 * @typedef {Object} IdentifyOptions
 * @type {object}
 */

/**
 * @typedef {Object} GroupOptions
 * @type {object}
 */

/**
 * @typedef {Object} MiddlewareExtra
 * @type {Object.<string, *>}
 */

/**
 * @typedef ApiKey
 * @type {object}
 * @property {string} development
 * @property {string} production
 */
export const ApiKey = {
  development: '',
  production: ''
};

export const SpecialEventType = {
  Identify: "Identify",
  Group: "Group"
}

/**
 * Default Amplitude configuration options. Contains tracking plan information.
 */
export const DefaultOptions = {
  plan: {
    version: '8',
    branch: 'main',
    source: '',
    versionId: ''
  }
};

export class Identify {
  constructor() {
    this.event_type = 'Identify';
  }
}

export class Group {
  constructor() {
    this.event_type = 'Group';
  }
}

// prettier-ignore
export class Ampli {
  constructor() {
    /* @type {AmplitudeClient|undefined} */
    this.amplitude = undefined;
    this.disabled = false;
    /* @type {Middleware[]} */
    this.middlewares = [];
  }

  /**
   * @return {AmplitudeClient}
   */
  get client() {
    this.isInitializedAndEnabled();
    return this.amplitude;
  }

  /**
   * @private
   * @return {boolean}
   */
  isInitializedAndEnabled() {
    if (!this.amplitude) {
      throw new Error('Ampli is not yet initialized. Have you called ampli.load() on app start?');
    }
    return !this.disabled;
  }

  /**
   * Initialize the Ampli SDK. Call once when your application starts.
   * @param {LoadOptions} [options] Configuration options to initialize the Ampli SDK with.
   */
  load(options) {
    this.disabled = options?.disabled ?? false;

    if (this.amplitude) {
      console.warn('WARNING: Ampli is already intialized. Ampli.load() should be called once at application startup.');
      return;
    }

    const env = options?.environment ?? 'development';
    const apiKey = options?.client?.apiKey ?? ApiKey[env];

    if (options?.client?.instance) {
      this.amplitude = options?.client?.instance;
    } else if (apiKey) {
      this.amplitude = amplitude.getInstance();
      this.amplitude?.init(apiKey, undefined, { ...DefaultOptions, ...(options?.client?.options ?? options?.client?.config) });
    } else {
      throw new Error("ampli.load() requires 'environment', 'client.apiKey', or 'client.instance'");
    }
  }

  /**
   * Identify a user.
   *
   * @param {string|undefined} userId The user's id.
   * @param {IdentifyOptions} [options] Optional event options.
   * @param {MiddlewareExtra} [extra] Extra unstructured data for middleware.
   */
  identify(userId, options, extra) {
    if (!this.isInitializedAndEnabled()) {
      return;
    }

    const event = {
      event_type: SpecialEventType.Identify,
      user_id: userId || options?.user_id,
      device_id: options?.device_id
    };
    this.runMiddleware({ event, extra }, payload => {
      const e = payload.event;
      if (e.user_id) {
        this.amplitude.setUserId(e.user_id);
      }
      if (e.device_id) {
        this.amplitude.setDeviceId(e.device_id);
      }
      const ampIdentify = new amplitude.Identify();
      if (e.event_properties != null) {
        for (const [key, value] of Object.entries(e.event_properties)) {
          ampIdentify.set(key, value);
        }
      }
      this.amplitude.identify(
        ampIdentify,
        options?.callback,
        options?.errorCallback
      );
    });
  }

  /**
   * Set Group for the current user
   *
   * @param {String} name
   * @param {String|String[]} value
   * @param {GroupOptions} [options]
   * @param {MiddlewareExtra} [extra]
   */
  setGroup(name, value, options, extra) {
    if (!this.isInitializedAndEnabled()) {
      return;
    }

    this.amplitude?.setGroup(name, value);
  }

  /**
   * Identify a group.
   *
   * @param {string} groupType The group type.
   * @param {string|string[]} groupName The group name.
   * @param {GroupOptions} [options] Options for this groupIdentify call.
   * @param {MiddlewareExtra} [extra] Extra untyped parameters for use in middleware.
   */
  groupIdentify(groupType, groupName, options, extra) {
    if (!this.isInitializedAndEnabled()) {
      return;
    }

    const event = {
      event_type: SpecialEventType.Group,
      user_id: options?.user_id,
      device_id: options?.device_id
    };
    this.runMiddleware({ event, extra }, payload => {
      const e = payload.event;
      if (e.user_id) {
        this.amplitude.setUserId(e.user_id);
      }
      if (e.device_id) {
        this.amplitude.setDeviceId(e.device_id);
      }
      const amplitudeIdentify = new amplitude.Identify();
      if (e.event_properties != null) {
        for (const [key, value] of Object.entries(e.event_properties)) {
          amplitudeIdentify.set(key, value);
        }
      }
      this.amplitude.groupIdentify(groupType, groupName, amplitudeIdentify, options?.callback);
    });
  }

  /**
   * Track event
   *
   * @param {BaseEvent} event The event to track.
   * @param {EventOptions} [options] Optional event options.
   * @param {MiddlewareExtra} [extra] Extra unstructured data for middleware.
   */
  track(event, options, extra) {
    if (!this.isInitializedAndEnabled()) {
      return;
    }

    this.runMiddleware({ event, extra }, payload => {
      this.amplitude.logEvent(
        payload.event.event_type,
        payload.event.event_properties,
        options?.callback,
        options?.errorCallback,
      );
    });
  }

  /**
   * Add new middleware to end of chain
   *
   * @param {Middleware} middleware
   */
  addEventMiddleware(middleware) {
    this.middlewares.push(middleware);
  }

  /**
   * Runs all middleware
   *
   * @param {MiddlewarePayload} payload
   * @param {MiddlewareNext} next The method to run after all middleware.
   *
   * @protected
   */
  runMiddleware(payload, next) {
    let curMiddlewareIndex = -1;
    const middlewareCount = this.middlewares.length;

    const middlewareNext = curPayload => {
      curMiddlewareIndex += 1;
      if (curMiddlewareIndex < middlewareCount) {
        this.middlewares[curMiddlewareIndex](curPayload, _next);
      } else {
        next(curPayload);
      }
    };

    const _next = middlewareCount > 0 ? middlewareNext : next;

    _next(payload);
  }
}

export const ampli = new Ampli();

@yuhao900914
Copy link
Contributor

Hi @Zaimwa9,
Thanks for adopting our ampli SDK!
Looks like your events don't link to any source. You need to create a source for the project and select the right runtime. Then go back to the events page and add the event to the source.

@Zaimwa9
Copy link
Author

Zaimwa9 commented May 4, 2022

Indeed I didn't connect the source to the event, you rock thanks !

@Zaimwa9
Copy link
Author

Zaimwa9 commented May 5, 2022

Sorry for disturbing @yuhao900914, now it's Segment as a destination that is not working :D.

API Keys all good ! Source website Javascript enabled on segment. But nothing happens. If ever you could help that'd be awesome (and my last question!)

Events are well tracked in Amplitude but nothing happens Segment side

@yuhao900914
Copy link
Contributor

If you are using ampli SDK, the event will be only sent to amplitude. But we provide the middleware function which allows you to forward the event to other services, like segment.
Did you implement the middleware? (https://developers.data.amplitude.com/middleware)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants